sujoydev99 commited on
Commit
146b1cb
·
1 Parent(s): 68fe061
Files changed (12) hide show
  1. .file +97 -0
  2. api/index.js +1730 -0
  3. cache.js +92 -0
  4. chat.html +337 -0
  5. functions.js +364 -0
  6. index.js +850 -58
  7. package.json +1 -0
  8. swagger.json +223 -21
  9. swagger.yaml +159 -19
  10. utils.js +1 -1
  11. vercel.json +15 -0
  12. yarn.lock +159 -1
.file ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * @swagger
3
+ * /company/{companyId}/departments:
4
+ * get:
5
+ * summary: Retrieve departments for a specific company
6
+ * description: Fetches a list of departments associated with the given company ID.
7
+ * tags: [Company]
8
+ * operationId: getCompanyDepartments
9
+ * parameters:
10
+ * - in: path
11
+ * name: companyId
12
+ * required: true
13
+ * schema:
14
+ * type: string
15
+ * description: The unique identifier of the company
16
+ * responses:
17
+ * 200:
18
+ * description: An array of department objects
19
+ * content:
20
+ * application/json:
21
+ * schema:
22
+ * type: array
23
+ * items:
24
+ * type: object
25
+ * properties:
26
+ * name:
27
+ * type: string
28
+ * description: Name of the department
29
+ * slug:
30
+ * type: string
31
+ * description: slug or identifier of the department
32
+ */
33
+
34
+ app.get("/company/:companyId/departments", async (req, res, next) => {
35
+ try {
36
+ const { companyId } = req.params;
37
+ const client = await initClient(companyId);
38
+ let departments = await client.catalog.listDepartmentsData({
39
+ isActive: true, pageSize: 100, pageNo: 1
40
+ });
41
+ departments = departments?.items?.map(i => { return { name: i.name, slug: i.slug } })
42
+ res.json(departments);
43
+
44
+ } catch (e) { next(e) }
45
+ })
46
+ /**
47
+ * @swagger
48
+ * /company/{companyId}/departments/{departmentSlug}:
49
+ * get:
50
+ * summary: Retrieve categories for a specific department
51
+ * description: Retrieve categories for a specific department.
52
+ * tags: [Company]
53
+ * operationId: getDepartmentCategories
54
+ * parameters:
55
+ * - in: path
56
+ * name: companyId
57
+ * required: true
58
+ * schema:
59
+ * type: string
60
+ * description: The unique identifier of the company
61
+ * - in: path
62
+ * name: departmentSlug
63
+ * required: true
64
+ * schema:
65
+ * type: string
66
+ * description: The unique skug of the department to get categories
67
+ * responses:
68
+ * 200:
69
+ * description: An array of department objects
70
+ * content:
71
+ * application/json:
72
+ * schema:
73
+ * type: array
74
+ * items:
75
+ * type: object
76
+ * properties:
77
+ * name:
78
+ * type: string
79
+ * description: Name of the category
80
+ * slug:
81
+ * type: string
82
+ * description: slug or identifier of the catrgory
83
+ */
84
+
85
+ app.get("/company/:companyId/departments/:departmentSlug", async (req, res, next) => {
86
+ try {
87
+ const { companyId, departmentSlug } = req.params;
88
+ const { item_type = 'single' } = req.query;
89
+ const client = await initClient(companyId);
90
+ let categories = await client.catalog.listProductTemplateCategories({
91
+ departments: departmentSlug, pageNo: 1, pageSize: 100, itemType: item_type
92
+ });
93
+ categories = categories?.items?.map(i => { return { name: i.name, slug: i.slug } })
94
+ res.json(categories);
95
+
96
+ } catch (e) { next(e) }
97
+ })
api/index.js ADDED
@@ -0,0 +1,1730 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from "express";
2
+ import Redis from "ioredis";
3
+ import { initClient } from './utils.js';
4
+ import { errorHandler } from './middleware.js';
5
+ import swaggerJSDoc from 'swagger-jsdoc';
6
+ import yaml from 'js-yaml'
7
+ import fs from 'fs';
8
+ import { RedisListCache } from './cache.js';
9
+ const listCache = new RedisListCache({ namespace: "fc" })
10
+ const redis = new Redis();
11
+
12
+ const app = express();
13
+ const port = process.env.PORT;
14
+ app.use(express.json({}));
15
+ const swaggerDefinition = {
16
+ openapi: '3.0.0',
17
+ info: {
18
+ title: 'Express API Documentation',
19
+ version: '1.0.0',
20
+ description: 'This is the API documentation for my Express application.'
21
+ },
22
+ servers: [{
23
+ url: "https://934a-45-119-30-178.ngrok-free.app"
24
+ }]
25
+ };
26
+ const options = {
27
+ swaggerDefinition,
28
+ // Path to the API docs
29
+ apis: ['./index.js'], // Adjust the path according to your file structure
30
+ };
31
+
32
+
33
+
34
+ /**
35
+ * @swagger
36
+ * components:
37
+ * schemas:
38
+ * CompanyCreds:
39
+ * type: object
40
+ * properties:
41
+ * clientId:
42
+ * type: string
43
+ * description: Client ID for the company
44
+ * clientSecret:
45
+ * type: string
46
+ * description: Client secret for the company
47
+ * required:
48
+ * - clientId
49
+ * - clientSecret
50
+ * CreateUpdateLocation:
51
+ * type: object
52
+ * required:
53
+ * - code
54
+ * - name
55
+ * - gst
56
+ * - manager
57
+ * - address
58
+ * properties:
59
+ * code:
60
+ * type: string
61
+ * description: Unique code for the location
62
+ * name:
63
+ * type: string
64
+ * description: Name of the location
65
+ * gst:
66
+ * type: object
67
+ * required:
68
+ * - legal_name
69
+ * - value
70
+ * properties:
71
+ * legal_name:
72
+ * type: string
73
+ * description: Legal name for GST purposes
74
+ * value:
75
+ * type: string
76
+ * description: GST value
77
+ * manager:
78
+ * type: object
79
+ * required:
80
+ * - manager_name
81
+ * - email
82
+ * - number
83
+ * - country_code
84
+ * properties:
85
+ * manager_name:
86
+ * type: string
87
+ * description: Name of the manager
88
+ * email:
89
+ * type: string
90
+ * description: Email of the manager
91
+ * number:
92
+ * type: string
93
+ * description: Contact number of the manager
94
+ * country_code:
95
+ * type: string
96
+ * description: Country code for the manager's contact number
97
+ * address:
98
+ * type: object
99
+ * required:
100
+ * - address1
101
+ * - country
102
+ * - pincode
103
+ * - city
104
+ * - state
105
+ * properties:
106
+ * address1:
107
+ * type: string
108
+ * description: Primary address line
109
+ * address2:
110
+ * type: string
111
+ * description: Secondary address line
112
+ * country:
113
+ * type: string
114
+ * description: Country of the location
115
+ * pincode:
116
+ * type: string
117
+ * description: Postal code of the location
118
+ * city:
119
+ * type: string
120
+ * description: City of the location
121
+ * state:
122
+ * type: string
123
+ * description: State of the location
124
+ * latitude:
125
+ * type: number
126
+ * description: Latitude for the location
127
+ * longitude:
128
+ * type: number
129
+ * description: Longitude for the location
130
+ * landmark:
131
+ * type: string
132
+ * description: Landmark near the location
133
+ * Brand:
134
+ * type: object
135
+ * properties:
136
+ * name:
137
+ * type: string
138
+ * logo:
139
+ * type: string
140
+ * id:
141
+ * type: string
142
+ * BrandCreation:
143
+ * type: object
144
+ * required:
145
+ * - name
146
+ * - logo
147
+ * - description
148
+ * properties:
149
+ * name:
150
+ * type: string
151
+ * logo:
152
+ * type: string
153
+ * description:
154
+ * type: string
155
+ * ErrorResponse:
156
+ * type: object
157
+ * properties:
158
+ * message:
159
+ * type: string
160
+ * description: Error message
161
+ */
162
+
163
+ app.get(['/swagger.yaml', '/swagger.json'], (req, res) => {
164
+ // Initialize swagger-jsdoc
165
+ const swaggerSpec = swaggerJSDoc(options);
166
+
167
+ // Convert to YAML
168
+ const swaggerYAML = yaml.dump(swaggerSpec);
169
+ switch (req.path.split('.').pop()) {
170
+ case 'json':
171
+ res.setHeader('Content-Type', 'application/json');
172
+ return res.send(JSON.stringify(swaggerSpec, null, 2));
173
+ case 'yaml':
174
+ res.setHeader('Content-Type', 'text/yaml');
175
+ return res.send(swaggerYAML);
176
+ }
177
+ });
178
+
179
+ /**
180
+ * @swagger
181
+ * /_healthz:
182
+ * get:
183
+ * operationId: getHealthZ
184
+ * description: Check server health
185
+ * responses:
186
+ * 200:
187
+ * description: Server is healthy
188
+ * content:
189
+ * text/plain:
190
+ * schema:
191
+ * type: string
192
+ * example: Hello World!
193
+ */
194
+ app.get("/_healthz", (req, res) => {
195
+ res.send('Hello World!');
196
+ });
197
+ app.get("/privacy", (req, res) => {
198
+ res.send('This is the privacy policy page!');
199
+ });
200
+
201
+ /**
202
+ * @swagger
203
+ * /company/{companyId}:
204
+ * get:
205
+ * operationId: getOrVerifyCompanyCredentials
206
+ * description: Retrieve company credentials
207
+ * tags: [Company]
208
+ * parameters:
209
+ * - in: path
210
+ * name: companyId
211
+ * required: true
212
+ * schema:
213
+ * type: string
214
+ * description: The company ID
215
+ * responses:
216
+ * 200:
217
+ * description: Company credentials retrieved successfully
218
+ * content:
219
+ * application/json:
220
+ * schema:
221
+ * $ref: '#/components/schemas/CompanyCreds'
222
+ * 404:
223
+ * description: Company credentials not found
224
+ * content:
225
+ * application/json:
226
+ * schema:
227
+ * $ref: '#/components/schemas/ErrorResponse'
228
+ */
229
+ app.get("/company/:companyId", async (req, res, next) => {
230
+ try {
231
+ const { companyId } = req.params;
232
+ const creds = await redis.get(`${companyId}:creds`);
233
+ if (!creds) {
234
+ throw {
235
+ message: "company creds not found"
236
+ }
237
+ }
238
+ res.json({ ...JSON.parse(creds), companyId })
239
+ } catch (e) {
240
+ next(e)
241
+ }
242
+ })
243
+
244
+ /**
245
+ * @swagger
246
+ * /company/{companyId}:
247
+ * put:
248
+ * operationId: updateCompanyCredentials
249
+ * description: Update company credentials
250
+ * tags: [Company]
251
+ * parameters:
252
+ * - in: path
253
+ * name: companyId
254
+ * required: true
255
+ * schema:
256
+ * type: string
257
+ * description: The company ID
258
+ * requestBody:
259
+ * required: true
260
+ * content:
261
+ * application/json:
262
+ * schema:
263
+ * $ref: '#/components/schemas/CompanyCreds'
264
+ * responses:
265
+ * 200:
266
+ * description: Company credentials updated successfully
267
+ * content:
268
+ * application/json:
269
+ * schema:
270
+ * type: object
271
+ * properties:
272
+ * message:
273
+ * type: string
274
+ * 400:
275
+ * description: Invalid input
276
+ * content:
277
+ * application/json:
278
+ * schema:
279
+ * $ref: '#/components/schemas/ErrorResponse'
280
+ */
281
+ app.put("/company/:companyId", async (req, res, next) => {
282
+ try {
283
+ const { companyId } = req.params;
284
+ const { clientId, clientSecret } = req.body
285
+ const creds = await redis.set(`${companyId}:creds`, JSON.stringify({ clientId, clientSecret }));
286
+ res.json({ message: "company creds saved" })
287
+ } catch (e) {
288
+ next(e)
289
+ }
290
+ })
291
+
292
+
293
+
294
+ /**
295
+ * @swagger
296
+ * /company/{companyId}/applications:
297
+ * get:
298
+ * operationId: getSalesChannelByCompany
299
+ * description: Retrieve applications for a specific company
300
+ * tags: [Company]
301
+ * parameters:
302
+ * - in: path
303
+ * name: companyId
304
+ * required: true
305
+ * schema:
306
+ * type: string
307
+ * description: The ID of the company to retrieve applications for
308
+ * responses:
309
+ * 200:
310
+ * description: List of applications for the specified company
311
+ * content:
312
+ * application/json:
313
+ * schema:
314
+ * type: array
315
+ * items:
316
+ * type: object
317
+ * properties:
318
+ * name:
319
+ * type: string
320
+ * description: Name of the application
321
+ * id:
322
+ * type: string
323
+ * description: ID of the application
324
+ * token:
325
+ * type: string
326
+ * description: Token associated with the application
327
+ * domain:
328
+ * type: string
329
+ * description: Primary domain of the application
330
+ * logo:
331
+ * type: string
332
+ * description: Logo URL of the application
333
+ * 500:
334
+ * description: Server error
335
+ * content:
336
+ * application/json:
337
+ * schema:
338
+ * $ref: '#/components/schemas/ErrorResponse'
339
+ */
340
+ app.get("/company/:companyId/applications", async (req, res, next) => {
341
+ try {
342
+ const { companyId } = req.params;
343
+ const client = await initClient(companyId);
344
+ let applications = await client.configuration.getApplications({ pageSize: 100 });
345
+ applications = applications.items.map(i => {
346
+ return {
347
+ name: i.name,
348
+ id: i.id,
349
+ token: i.token,
350
+ domain: i.domains?.find(i => i.is_primary)?.name,
351
+ logo: i.logo?.secure_url
352
+ }
353
+ })
354
+ res.json(applications)
355
+ } catch (e) {
356
+ next(e)
357
+ }
358
+ })
359
+
360
+ /**
361
+ * @swagger
362
+ * /company/{companyId}/brands:
363
+ * get:
364
+ * summary: Retrieves a list of brands for a specific company
365
+ * tags: [Brands]
366
+ * operationId: getCompanyBrands
367
+ * description: Fetches a list of brands associated with the given company ID.
368
+ * parameters:
369
+ * - in: path
370
+ * name: companyId
371
+ * required: true
372
+ * schema:
373
+ * type: string
374
+ * description: The unique identifier of the company
375
+ * responses:
376
+ * 200:
377
+ * description: A list of brands
378
+ * content:
379
+ * application/json:
380
+ * schema:
381
+ * type: array
382
+ * items:
383
+ * $ref: '#/components/schemas/Brand'
384
+ */
385
+ app.get("/company/:companyId/brands", async (req, res, next) => {
386
+ try {
387
+ const { companyId } = req.params;
388
+ const client = await initClient(companyId);
389
+ let brands = await client.companyProfile.getBrands({ pageSize: 300 });
390
+ brands = brands.items.map(i => {
391
+ return {
392
+ name: i?.brand?.name,
393
+ logo: i?.brand?.logo,
394
+ id: i?.brand?.uid,
395
+ }
396
+ })
397
+ res.json(brands)
398
+ } catch (e) {
399
+ next(e)
400
+ }
401
+ })
402
+
403
+ /**
404
+ * @swagger
405
+ * /company/{companyId}/brands:
406
+ * post:
407
+ * summary: Creates a new brand for a specific company
408
+ * tags: [Brands]
409
+ * operationId: createCompanyBrand
410
+ * description: Adds a new brand to the company profile.
411
+ * parameters:
412
+ * - in: path
413
+ * name: companyId
414
+ * required: true
415
+ * schema:
416
+ * type: string
417
+ * description: The unique identifier of the company
418
+ * requestBody:
419
+ * required: true
420
+ * content:
421
+ * application/json:
422
+ * schema:
423
+ * $ref: '#/components/schemas/BrandCreation'
424
+ * responses:
425
+ * 200:
426
+ * description: Brand created successfully
427
+ * content:
428
+ * application/json:
429
+ * schema:
430
+ * type: object
431
+ * properties:
432
+ * message:
433
+ * type: string
434
+ * id:
435
+ * type: string
436
+ *
437
+ * /company/{companyId}/brands/{brandId}:
438
+ * put:
439
+ * summary: Creates a new brand for a specific company
440
+ * tags: [Brands]
441
+ * operationId: updateCompanyBrand
442
+ * description: updated an existing brand.
443
+ * parameters:
444
+ * - in: path
445
+ * name: companyId
446
+ * required: true
447
+ * schema:
448
+ * type: string
449
+ * description: The unique identifier of the company
450
+ * - in: path
451
+ * name: brandId
452
+ * required: true
453
+ * schema:
454
+ * type: number
455
+ * description: The unique identifier of the brand
456
+ * requestBody:
457
+ * required: true
458
+ * content:
459
+ * application/json:
460
+ * schema:
461
+ * $ref: '#/components/schemas/BrandCreation'
462
+ * responses:
463
+ * 200:
464
+ * description: Brand updated successfully
465
+ * content:
466
+ * application/json:
467
+ * schema:
468
+ * type: object
469
+ * properties:
470
+ * message:
471
+ * type: string
472
+ * id:
473
+ * type: string
474
+ */
475
+ app.post("/company/:companyId/brands", async (req, res, next) => {
476
+ try {
477
+ const { companyId } = req.params;
478
+ const client = await initClient(companyId);
479
+ const {
480
+ name,
481
+ logo = "https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/fyprod/wrkr/platform/pictures/favicon/original/ZWTmgEoFQ-platform-favicon.png",
482
+ description
483
+ } = req.body
484
+ let brands = await client.companyProfile.createBrand({
485
+ body: {
486
+ name,
487
+ description,
488
+ logo,
489
+ banner: { portrait: logo, landscape: logo }
490
+ }
491
+ });
492
+ res.json({ message: "brand created", id: brands?.id })
493
+ } catch (e) {
494
+ next(e)
495
+ }
496
+ })
497
+ app.put("/company/:companyId/brands/:brandId", async (req, res, next) => {
498
+ try {
499
+ const { companyId, brandId } = req.params;
500
+ const client = await initClient(companyId);
501
+ const {
502
+ name,
503
+ logo = "https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/fyprod/wrkr/platform/pictures/favicon/original/ZWTmgEoFQ-platform-favicon.png",
504
+ description
505
+ } = req.body
506
+ let brands = await client.companyProfile.editBrand({
507
+ brandId,
508
+ body: {
509
+ name,
510
+ description,
511
+ logo,
512
+ banner: { portrait: logo, landscape: logo }
513
+ }
514
+ });
515
+ res.json({ message: "brand updated", id: brands?.id })
516
+ } catch (e) {
517
+ next(e)
518
+ }
519
+ })
520
+
521
+ /**
522
+ * @swagger
523
+ * /company/{companyId}/locations:
524
+ * get:
525
+ * operationId: getLocationsByCompany
526
+ * description: get all company locations
527
+ * tags: [Company]
528
+ * parameters:
529
+ * - in: path
530
+ * name: companyId
531
+ * required: true
532
+ * schema:
533
+ * type: string
534
+ * description: The ID of the company to add a location for
535
+ * responses:
536
+ * 200:
537
+ * description: location list
538
+ * content:
539
+ * application/json:
540
+ * schema:
541
+ * type: array
542
+ * items:
543
+ * properties:
544
+ * id:
545
+ * type: number
546
+ * description: Location id
547
+ * code:
548
+ * type: string
549
+ * description: Location code
550
+ * name:
551
+ * type: string
552
+ * description: Location code
553
+ * documents:
554
+ * type: array
555
+ * description: Location gst documents
556
+ * items:
557
+ * type: object
558
+ * properties:
559
+ * type:
560
+ * type: string
561
+ * description: document type
562
+ * value:
563
+ * type: string
564
+ * description: document number
565
+ * verified:
566
+ * type: boolean
567
+ * description: document number verification status
568
+ * legal_name:
569
+ * type: boolean
570
+ * description: document owner
571
+ * 400:
572
+ * description: Invalid input
573
+ * content:
574
+ * application/json:
575
+ * schema:
576
+ * $ref: '#/components/schemas/ErrorResponse'
577
+ */
578
+ app.get("/company/:companyId/locations", async (req, res, next) => {
579
+ try {
580
+ const { companyId } = req.params;
581
+ const client = await initClient(companyId.toString());
582
+ let locations = await client.companyProfile.getLocations({ pageSize: 100 });
583
+ locations = locations.items.map(i => {
584
+ return {
585
+ name: i.name,
586
+ id: i.uid,
587
+ code: i.code,
588
+ documents: i.documents
589
+ }
590
+ })
591
+ res.json(locations)
592
+ } catch (e) {
593
+ next(e)
594
+ }
595
+ })
596
+ /**
597
+ * @swagger
598
+ * /company/{companyId}/locations:
599
+ * post:
600
+ * operationId: createLocationsForCompany
601
+ * description: Add a new location for a specific company
602
+ * tags: [Company]
603
+ * parameters:
604
+ * - in: path
605
+ * name: companyId
606
+ * required: true
607
+ * schema:
608
+ * type: string
609
+ * description: The ID of the company to add a location for
610
+ * requestBody:
611
+ * required: true
612
+ * content:
613
+ * application/json:
614
+ * schema:
615
+ * $ref: '#/components/schemas/CreateUpdateLocation'
616
+ * responses:
617
+ * 200:
618
+ * description: Location created successfully
619
+ * content:
620
+ * application/json:
621
+ * schema:
622
+ * type: object
623
+ * properties:
624
+ * message:
625
+ * type: string
626
+ * id:
627
+ * type: string
628
+ * description: Location id
629
+ * 400:
630
+ * description: Invalid input
631
+ * content:
632
+ * application/json:
633
+ * schema:
634
+ * $ref: '#/components/schemas/ErrorResponse'
635
+ * /company/{companyId}/locations/{locationId}:
636
+ * put:
637
+ * operationId: updateLocationByCompany
638
+ * description: update a location for a specific company
639
+ * tags: [Company]
640
+ * parameters:
641
+ * - in: path
642
+ * name: companyId
643
+ * required: true
644
+ * schema:
645
+ * type: string
646
+ * description: The ID of the company to add a location for
647
+ * - in: path
648
+ * name: locationId
649
+ * required: true
650
+ * schema:
651
+ * type: string
652
+ * description: The ID of the location to be updated
653
+ * requestBody:
654
+ * required: true
655
+ * content:
656
+ * application/json:
657
+ * schema:
658
+ * $ref: '#/components/schemas/CreateUpdateLocation'
659
+ * responses:
660
+ * 200:
661
+ * description: Location updated successfully
662
+ * content:
663
+ * application/json:
664
+ * schema:
665
+ * type: object
666
+ * properties:
667
+ * message:
668
+ * type: string
669
+ * id:
670
+ * type: string
671
+ * description: Location id
672
+ * 400:
673
+ * description: Invalid input
674
+ * content:
675
+ * application/json:
676
+ * schema:
677
+ * $ref: '#/components/schemas/ErrorResponse'
678
+ */
679
+ app.post("/company/:companyId/locations", async (req, res, next) => {
680
+ try {
681
+ const { companyId } = req.params;
682
+ const { code,
683
+ name,
684
+ gst: {
685
+ legal_name,
686
+ value
687
+ },
688
+ manager: {
689
+ manager_name, email, number, country_code
690
+ },
691
+ address: {
692
+ address1,
693
+ address2,
694
+ country,
695
+ pincode,
696
+ city,
697
+ state,
698
+ latitude = 19.2762702,
699
+ longitude = 72.8929,
700
+ landmark = ""
701
+ },
702
+
703
+ } = req.body
704
+ const client = await initClient(companyId);
705
+ let locations = await client.companyProfile.createLocation({
706
+ body: {
707
+ name,
708
+ display_name: name,
709
+ code,
710
+ company: parseInt(companyId),
711
+ documents: [{
712
+ type: "gst",
713
+ legal_name: legal_name,
714
+ value: value, verified: true
715
+ }],
716
+ address: {
717
+ "address1": address1,
718
+ "address2": address2,
719
+ "country": country,
720
+ "pincode": pincode,
721
+ "city": city,
722
+ "state": state,
723
+ "latitude": latitude,
724
+ "longitude": longitude,
725
+ "landmark": landmark
726
+ },
727
+ manager: {
728
+ "name": manager_name,
729
+ "email": email,
730
+ "mobile_no": {
731
+ "number": number,
732
+ "country_code": country_code
733
+ }
734
+ },
735
+ contact_numbers: [
736
+ {
737
+ "number": number,
738
+ "country_code": country_code
739
+ }
740
+ ],
741
+ store_type: "high_street"
742
+
743
+ }
744
+ });
745
+
746
+ res.json({ message: "location added", id: locations?.id })
747
+ } catch (e) {
748
+ next(e)
749
+ }
750
+ })
751
+ app.put("/company/:companyId/locations/locationId", async (req, res, next) => {
752
+ try {
753
+ const { companyId } = req.params;
754
+ const { code,
755
+ name,
756
+ gst: {
757
+ legal_name,
758
+ value
759
+ },
760
+ manager: {
761
+ manager_name, email, number, country_code
762
+ },
763
+ address: {
764
+ address1,
765
+ address2,
766
+ country,
767
+ pincode,
768
+ city,
769
+ state,
770
+ latitude = 19.2762702,
771
+ longitude = 72.8929,
772
+ landmark = ""
773
+ },
774
+
775
+ } = req.body
776
+ const client = await initClient(companyId);
777
+ let locations = await client.companyProfile.createLocation({
778
+ body: {
779
+ name,
780
+ display_name: name,
781
+ code,
782
+ company: parseInt(companyId),
783
+ documents: [{
784
+ type: "gst",
785
+ legal_name: legal_name,
786
+ value: value, verified: true
787
+ }],
788
+ address: {
789
+ "address1": address1,
790
+ "address2": address2,
791
+ "country": country,
792
+ "pincode": pincode,
793
+ "city": city,
794
+ "state": state,
795
+ "latitude": latitude,
796
+ "longitude": longitude,
797
+ "landmark": landmark
798
+ },
799
+ manager: {
800
+ "name": manager_name,
801
+ "email": email,
802
+ "mobile_no": {
803
+ "number": number,
804
+ "country_code": country_code
805
+ }
806
+ },
807
+ contact_numbers: [
808
+ {
809
+ "number": number,
810
+ "country_code": country_code
811
+ }
812
+ ],
813
+ store_type: "high_street"
814
+
815
+ }
816
+ });
817
+
818
+ res.json({ message: "location updated", id: locations?.id })
819
+ } catch (e) {
820
+ next(e)
821
+ }
822
+ })
823
+
824
+
825
+
826
+ /**
827
+ * @swagger
828
+ * /company/{companyId}/products:
829
+ * post:
830
+ * summary: Creates a new product for a given company.
831
+ * description: This endpoint creates a new product with various attributes including name, slug, pricing, and more.
832
+ * operationId: createProduct
833
+ * tags:
834
+ * - Products
835
+ * parameters:
836
+ * - in: path
837
+ * name: companyId
838
+ * required: true
839
+ * schema:
840
+ * type: string
841
+ * description: Unique identifier of the company.
842
+ * requestBody:
843
+ * required: true
844
+ * content:
845
+ * application/json:
846
+ * schema:
847
+ * type: object
848
+ * required:
849
+ * - name
850
+ * - slug
851
+ * - seller_identifier
852
+ * - brand_id
853
+ * properties:
854
+ * name:
855
+ * type: string
856
+ * description: Name of the product.
857
+ * slug:
858
+ * type: string
859
+ * description: URL-friendly identifier for the product.
860
+ * seller_identifier:
861
+ * type: string
862
+ * description: Unique identifier for the seller.
863
+ * brand_id:
864
+ * type: string
865
+ * description: Unique identifier for the brand.
866
+ * location_id:
867
+ * type: string
868
+ * description: Location identifier for the product.
869
+ * mrp:
870
+ * type: number
871
+ * default: 999
872
+ * description: Maximum retail price of the product.
873
+ * selling_price:
874
+ * type: number
875
+ * default: 499
876
+ * description: Selling price of the product.
877
+ * responses:
878
+ * 200:
879
+ * description: Successful creation of the product.
880
+ * content:
881
+ * application/json:
882
+ * schema:
883
+ * type: object
884
+ * properties:
885
+ * message:
886
+ * type: string
887
+ * id:
888
+ * type: string
889
+ * seller_identifier:
890
+ * type: string
891
+ */
892
+
893
+ app.post("/company/:companyId/products", async (req, res, next) => {
894
+ try {
895
+ const { companyId } = req.params;
896
+ const { name,
897
+ slug,
898
+ seller_identifier,
899
+ brand_id, location_id, mrp = 999, selling_price = 499
900
+ } = req.body;
901
+ const obj = {
902
+ "name": name,
903
+ "slug": slug,
904
+ "brand_uid": brand_id,
905
+ "item_code": seller_identifier,
906
+ "teaser_tag": {},
907
+ "net_quantity": {},
908
+ "tax_identifier": {
909
+ "reporting_hsn": "1202355241H1",
910
+ "hsn_code": "1202355241",
911
+ "hsn_code_id": "65769883ba99dcf407a2b1ed"
912
+ },
913
+ "country_of_origin": "India",
914
+ "variants": {},
915
+ "variant_media": {},
916
+ "description": "PHA+WW91ciBwcm9kdWN0IGRlc2NyaXB0aW9uPC9wPg==",
917
+ "short_description": "Your product description",
918
+ "highlights": [],
919
+ "company_id": 10,
920
+ "template_tag": "c2-0-template",
921
+ "currency": "INR",
922
+ "media": [],
923
+ "is_set": false,
924
+ "sizes": [
925
+ {
926
+ "size": "OS",
927
+ "price": mrp,
928
+ "price_effective": selling_price,
929
+ "price_transfer": 0,
930
+ "currency": "INR",
931
+ "item_length": 1,
932
+ "item_width": 1,
933
+ "item_height": 1,
934
+ "item_weight": 1,
935
+ "item_dimensions_unit_of_measure": "cm",
936
+ "item_weight_unit_of_measure": "gram",
937
+ "track_inventory": true,
938
+ "identifiers": [
939
+ {
940
+ "gtin_value": seller_identifier,
941
+ "gtin_type": "ean",
942
+ "primary": true
943
+ }
944
+ ],
945
+ "_custom_json": {},
946
+ "name": "OS"
947
+ }
948
+ ],
949
+ "_custom_json": {},
950
+ "size_guide": "",
951
+ "product_group_tag": [],
952
+ "product_publish": {
953
+ "product_online_date": "2023-12-11T08:38:10.082Z",
954
+ "is_set": false
955
+ },
956
+ "is_active": true,
957
+ "custom_order": {
958
+ "is_custom_order": false,
959
+ "manufacturing_time": 0,
960
+ "manufacturing_time_unit": "hours"
961
+ },
962
+ "multi_size": false,
963
+ "no_of_boxes": 1,
964
+ "is_dependent": false,
965
+ "item_type": "digital",
966
+ "tags": [],
967
+ "departments": [
968
+ 19771
969
+ ],
970
+ return_config: {
971
+ "returnable": false
972
+ },
973
+ "category_slug": "c2-0-cat",
974
+ "trader": [
975
+ {
976
+ "type": "Manufacturer",
977
+ "name": "Manufacturer",
978
+ "address": [
979
+ "Manufacturer Address"
980
+ ]
981
+ }
982
+ ],
983
+ "return_config": {
984
+ "returnable": true,
985
+ time: 3,
986
+ unit: "days"
987
+ }
988
+ }
989
+ const client = await initClient(companyId);
990
+ let product = await client.catalog.createProduct({
991
+ body: obj
992
+ });
993
+ product = await client.catalog.getProduct({
994
+ itemId: product.uid
995
+ });
996
+ res.json({
997
+ message: "product created",
998
+ id: product.data.uid,
999
+ seller_identifier: product?.data?.sizes?.[0]?.seller_identifier
1000
+ });
1001
+ } catch (e) { next(e) }
1002
+ })
1003
+
1004
+ /**
1005
+ * @swagger
1006
+ * /company/{companyId}/products/{productId}/inventory:
1007
+ * post:
1008
+ * summary: Updates inventory for a specific product.
1009
+ * description: This endpoint updates the inventory details for a given product, including location, pricing, and quantity.
1010
+ * operationId: updateInventory
1011
+ * tags:
1012
+ * - Inventory
1013
+ * parameters:
1014
+ * - in: path
1015
+ * name: companyId
1016
+ * required: true
1017
+ * schema:
1018
+ * type: string
1019
+ * description: Unique identifier of the company.
1020
+ * - in: path
1021
+ * name: productId
1022
+ * required: true
1023
+ * schema:
1024
+ * type: string
1025
+ * description: Unique identifier of the product.
1026
+ * requestBody:
1027
+ * required: true
1028
+ * content:
1029
+ * application/json:
1030
+ * schema:
1031
+ * type: object
1032
+ * required:
1033
+ * - location_id
1034
+ * - seller_identifier
1035
+ * properties:
1036
+ * location_id:
1037
+ * type: string
1038
+ * description: Location identifier where the inventory is stored.
1039
+ * mrp:
1040
+ * type: number
1041
+ * default: 999
1042
+ * description: Maximum retail price of the product.
1043
+ * selling_price:
1044
+ * type: number
1045
+ * default: 499
1046
+ * description: Selling price of the product.
1047
+ * seller_identifier:
1048
+ * type: string
1049
+ * description: Unique identifier for the seller.
1050
+ * responses:
1051
+ * 200:
1052
+ * description: Successful update of inventory.
1053
+ * content:
1054
+ * application/json:
1055
+ * schema:
1056
+ * type: object
1057
+ * properties:
1058
+ * message:
1059
+ * type: string
1060
+ */
1061
+ app.post("/company/:companyId/products/:productId/inventory", async (req, res, next) => {
1062
+ try {
1063
+ const { companyId, productId } = req.params;
1064
+ const { location_id, mrp = 999, selling_price = 499, id, seller_identifier } = req.body;
1065
+ const client = await initClient(companyId);
1066
+ let product = await client.catalog.getProduct({
1067
+ itemId: productId
1068
+ });
1069
+ let inv = await client.catalog.updateRealtimeInventory({
1070
+ itemId: product.data.uid,
1071
+ sellerIdentifier: seller_identifier,
1072
+ body: {
1073
+ company_id: companyId,
1074
+ payload: [{
1075
+ "seller_identifier": seller_identifier,
1076
+ "store_id": location_id,
1077
+ "price_marked": mrp,
1078
+ "price_effective": selling_price,
1079
+ "total_quantity": 10,
1080
+ "tags": []
1081
+ }]
1082
+ }
1083
+ })
1084
+
1085
+ res.json({ message: "inv created" });
1086
+ } catch (e) { next(e) }
1087
+ })
1088
+
1089
+
1090
+ /**
1091
+ * @swagger
1092
+ * /company/{companyId}/sales_channel:
1093
+ * post:
1094
+ * operationId: addSalesChannel
1095
+ * summary: Create a sales channel for a given company
1096
+ * description: This endpoint creates a new sales channel for the specified company.
1097
+ * tags:
1098
+ * - Sales Channel
1099
+ * parameters:
1100
+ * - in: path
1101
+ * name: companyId
1102
+ * required: true
1103
+ * schema:
1104
+ * type: string
1105
+ * description: The ID of the company
1106
+ * requestBody:
1107
+ * required: true
1108
+ * content:
1109
+ * application/json:
1110
+ * schema:
1111
+ * type: object
1112
+ * properties:
1113
+ * brand_ids:
1114
+ * type: array
1115
+ * items:
1116
+ * type: integer
1117
+ * description: Array of brand IDs to be associated with the sales channel
1118
+ * name:
1119
+ * type: string
1120
+ * description: Name of the sales channel
1121
+ * subdomain:
1122
+ * type: string
1123
+ * description: subdomain associated with the sales channel
1124
+ * responses:
1125
+ * 200:
1126
+ * description: Sales channel successfully created
1127
+ * content:
1128
+ * application/json:
1129
+ * schema:
1130
+ * type: object
1131
+ * properties:
1132
+ * message:
1133
+ * type: string
1134
+ * app:
1135
+ * type: object
1136
+ * description: Details of the created sales channel
1137
+ * 400:
1138
+ * description: Bad request
1139
+ * 500:
1140
+ * description: Internal server error
1141
+ */
1142
+
1143
+ app.post("/company/:companyId/sales_channel", async (req, res, next) => {
1144
+ try {
1145
+ const { companyId } = req.params;
1146
+ const { brand_ids, name, subdomain } = req.body;
1147
+ const client = await initClient(companyId);
1148
+
1149
+ let app = await client.configuration.createApplication({
1150
+ body: {
1151
+ "app": {
1152
+ "company_id": (1).toString(),
1153
+ "channel_type": "website-and-mobile-apps",
1154
+ "auth": {
1155
+ "enabled": true
1156
+ },
1157
+ "name": name,
1158
+ "desc": "",
1159
+ "mode": "live"
1160
+ },
1161
+ "configuration": {
1162
+ "inventory": {
1163
+ "brand": {
1164
+ "criteria": "all",
1165
+ "brands": []
1166
+ },
1167
+ "store": {
1168
+ "criteria": "filter",
1169
+ "rules": [
1170
+ {
1171
+ "companies": [companyId],
1172
+ "brands": brand_ids
1173
+ }
1174
+ ],
1175
+ "stores": []
1176
+ },
1177
+ "image": ["standard", "substandard", "default"],
1178
+ "franchise_enabled": false,
1179
+ "out_of_stock": true
1180
+ },
1181
+ "payment": {
1182
+ "mode_of_payment": "ECOMM",
1183
+ "source": "ECOMM"
1184
+ },
1185
+ "article_assignment": {
1186
+ "post_order_reassignment": true,
1187
+ "enforced_stores": [],
1188
+ "rules": {
1189
+ "store_priority": {
1190
+ "enabled": false,
1191
+ "storetype_order": []
1192
+ }
1193
+ }
1194
+ }
1195
+ },
1196
+ "domain": {
1197
+ "name": `${subdomain}.hostx5.de`
1198
+ }
1199
+ }
1200
+ })
1201
+
1202
+ res.json({ message: "inv created", app });
1203
+ } catch (e) { next(e) }
1204
+ })
1205
+
1206
+ const chatHtml = fs.readFileSync('./chat.html', 'utf-8');
1207
+
1208
+ app.get('/', async (req, res, next) => {
1209
+ try {
1210
+ res.send(chatHtml);
1211
+ } catch (error) {
1212
+ console.error(error);
1213
+ res.send('Something needs to be fixed!');
1214
+ }
1215
+ });
1216
+
1217
+ app.get('/talk', async (req, res, next) => {
1218
+ try {
1219
+ res.send(chatHtml);
1220
+ } catch (error) {
1221
+ console.error(error);
1222
+ res.send('Something needs to be fixed!');
1223
+ }
1224
+ });
1225
+
1226
+ app.post(
1227
+ '/openai',
1228
+ async (req, res, next) => {
1229
+ const functions = [
1230
+ {
1231
+ "type": "function",
1232
+ "function": {
1233
+ "name": "getCompanyCreds",
1234
+ "description": "Retrieves credentials for a specific company based on its ID.",
1235
+ "parameters": {
1236
+ "type": "object",
1237
+ "properties": {
1238
+ "company_id": {
1239
+ "type": "number",
1240
+ "description": "Unique identifier of the company."
1241
+ }
1242
+ },
1243
+ "required": ["company_id"]
1244
+ }
1245
+ }
1246
+ },
1247
+ {
1248
+ "type": "function",
1249
+ "function": {
1250
+ "name": "createUpdateCompanyCreds",
1251
+ "description": "Creates or updates credentials for a company.",
1252
+ "parameters": {
1253
+ "type": "object",
1254
+ "properties": {
1255
+ "company_id": {
1256
+ "type": "number",
1257
+ "description": "Unique identifier of the company."
1258
+ },
1259
+ "clientId": {
1260
+ "type": "string",
1261
+ "description": "Client ID for authentication."
1262
+ },
1263
+ "clientSecret": {
1264
+ "type": "string",
1265
+ "description": "Client secret for authentication."
1266
+ }
1267
+ },
1268
+ "required": ["company_id", "clientId", "clientSecret"]
1269
+ }
1270
+ }
1271
+ },
1272
+ {
1273
+ "type": "function",
1274
+ "function": {
1275
+ "name": "getApplications",
1276
+ "description": "Retrieves a list of applications associated with a specific company ID.",
1277
+ "parameters": {
1278
+ "type": "object",
1279
+ "properties": {
1280
+ "company_id": {
1281
+ "type": "number",
1282
+ "description": "Unique identifier of the company."
1283
+ }
1284
+ },
1285
+ "required": ["company_id"]
1286
+ }
1287
+ }
1288
+ },
1289
+ {
1290
+ "type": "function",
1291
+ "function": {
1292
+ "name": "createBrand",
1293
+ "description": "Creates a new brand under a specific company.",
1294
+ "parameters": {
1295
+ "type": "object",
1296
+ "properties": {
1297
+ "company_id": {
1298
+ "type": "number",
1299
+ "description": "Unique identifier of the company."
1300
+ },
1301
+ "name": {
1302
+ "type": "string",
1303
+ "description": "Name of the new brand."
1304
+ },
1305
+ "description": {
1306
+ "type": "string",
1307
+ "description": "Description of the new brand."
1308
+ },
1309
+ "logo": {
1310
+ "type": "string",
1311
+ "description": "URL of the brand's logo."
1312
+ }
1313
+ },
1314
+ "required": ["company_id", "name", "description"]
1315
+ }
1316
+ }
1317
+ },
1318
+ {
1319
+ "type": "function",
1320
+ "function": {
1321
+ "name": "updateBrand",
1322
+ "description": "Updates the details of an existing brand within a company.",
1323
+ "parameters": {
1324
+ "type": "object",
1325
+ "properties": {
1326
+ "company_id": {
1327
+ "type": "number",
1328
+ "description": "Unique identifier of the company."
1329
+ },
1330
+ "brand_id": {
1331
+ "type": "string",
1332
+ "description": "Unique identifier of the brand to be updated."
1333
+ },
1334
+ "name": {
1335
+ "type": "string",
1336
+ "description": "New name for the brand."
1337
+ },
1338
+ "description": {
1339
+ "type": "string",
1340
+ "description": "New description for the brand."
1341
+ },
1342
+ "logo": {
1343
+ "type": "string",
1344
+ "description": "New URL for the brand's logo."
1345
+ },
1346
+ },
1347
+ "required": ["company_id", "brand_id", "name", "description"]
1348
+ }
1349
+ }
1350
+ },
1351
+ {
1352
+ "type": "function",
1353
+ "function": {
1354
+ "name": "getBrands",
1355
+ "description": "Retrieves a list of all brands associated with a specific company.",
1356
+ "parameters": {
1357
+ "type": "object",
1358
+ "properties": {
1359
+ "company_id": {
1360
+ "type": "number",
1361
+ "description": "Unique identifier of the company for which brands are being retrieved."
1362
+ }
1363
+ },
1364
+ "required": ["company_id"]
1365
+ }
1366
+ }
1367
+ },
1368
+ {
1369
+ "type": "function",
1370
+ "function": {
1371
+ "name": "getLocations",
1372
+ "description": "Retrieves a list of all locations associated with a specific company.",
1373
+ "parameters": {
1374
+ "type": "object",
1375
+ "properties": {
1376
+ "company_id": {
1377
+ "type": "number",
1378
+ "description": "Unique identifier of the company for which locations are being retrieved."
1379
+ }
1380
+ },
1381
+ "required": ["company_id"]
1382
+ }
1383
+ }
1384
+ },
1385
+ {
1386
+ "type": "function",
1387
+ "function": {
1388
+ "name": "createLocation",
1389
+ "description": "Creates a new location for a specified company.",
1390
+ "parameters": {
1391
+ "type": "object",
1392
+ "properties": {
1393
+ "company_id": {
1394
+ "type": "number",
1395
+ "description": "Unique identifier of the company."
1396
+ },
1397
+ "address1": {
1398
+ "type": "string",
1399
+ "description": "Primary address line of the new location."
1400
+ },
1401
+ "address2": {
1402
+ "type": "string",
1403
+ "description": "Secondary address line of the new location."
1404
+ },
1405
+ "pincode": {
1406
+ "type": "string",
1407
+ "description": "Postal code of the new location."
1408
+ },
1409
+ "state": {
1410
+ "type": "string",
1411
+ "description": "State where the new location is situated."
1412
+ },
1413
+ "city": {
1414
+ "type": "string",
1415
+ "description": "City where the new location is situated."
1416
+ },
1417
+ "number": {
1418
+ "type": "string",
1419
+ "description": "Contact number for the new location."
1420
+ },
1421
+ "country_code": {
1422
+ "type": "string",
1423
+ "description": "Country code for the contact number."
1424
+ },
1425
+ "gst_name": {
1426
+ "type": "string",
1427
+ "description": "GST registered name associated with the new location."
1428
+ },
1429
+ "gst_no": {
1430
+ "type": "string",
1431
+ "description": "GST number associated with the new location."
1432
+ },
1433
+ "latitude": {
1434
+ "type": "number",
1435
+ "description": "Latitude coordinate for the new location."
1436
+ },
1437
+ "longitude": {
1438
+ "type": "number",
1439
+ "description": "Longitude coordinate for the new location."
1440
+ }
1441
+ },
1442
+ "required": ["company_id", "address1", "city", "state", "pincode", "country_code", "gst_name", "gst_no"]
1443
+ }
1444
+ }
1445
+ },
1446
+ {
1447
+ "type": "function",
1448
+ "function": {
1449
+ "name": "updateLocation",
1450
+ "description": "update a existing location for a specified company.",
1451
+ "parameters": {
1452
+ "type": "object",
1453
+ "properties": {
1454
+ "company_id": {
1455
+ "type": "number",
1456
+ "description": "Unique identifier of the company."
1457
+ },
1458
+ "location_id": {
1459
+ "type": "number",
1460
+ "description": "Unique identifier of the location."
1461
+ },
1462
+ "address1": {
1463
+ "type": "string",
1464
+ "description": "Primary address line of the new location."
1465
+ },
1466
+ "address2": {
1467
+ "type": "string",
1468
+ "description": "Secondary address line of the new location."
1469
+ },
1470
+ "pincode": {
1471
+ "type": "string",
1472
+ "description": "Postal code of the new location."
1473
+ },
1474
+ "state": {
1475
+ "type": "string",
1476
+ "description": "State where the new location is situated."
1477
+ },
1478
+ "city": {
1479
+ "type": "string",
1480
+ "description": "City where the new location is situated."
1481
+ },
1482
+ "number": {
1483
+ "type": "string",
1484
+ "description": "Contact number for the new location."
1485
+ },
1486
+ "country_code": {
1487
+ "type": "string",
1488
+ "description": "Country code for the contact number."
1489
+ },
1490
+ "gst_name": {
1491
+ "type": "string",
1492
+ "description": "GST registered name associated with the new location."
1493
+ },
1494
+ "gst_no": {
1495
+ "type": "string",
1496
+ "description": "GST number associated with the new location."
1497
+ },
1498
+ "latitude": {
1499
+ "type": "number",
1500
+ "description": "Latitude coordinate for the new location."
1501
+ },
1502
+ "longitude": {
1503
+ "type": "number",
1504
+ "description": "Longitude coordinate for the new location."
1505
+ }
1506
+ },
1507
+ "required": ["company_id", 'brand_id', "address1", "city", "state", "pincode", "country_code", "gst_name", "gst_no"]
1508
+ }
1509
+ }
1510
+ },
1511
+ {
1512
+ "type": "function",
1513
+ "function": {
1514
+ "name": "createProduct",
1515
+ "description": "Creates a new product in the company's catalog.",
1516
+ "parameters": {
1517
+ "type": "object",
1518
+ "properties": {
1519
+ "name": {
1520
+ "type": "string",
1521
+ "description": "Name of the new product."
1522
+ },
1523
+ "company_id": {
1524
+ "type": "number",
1525
+ "description": "Unique identifier of the company."
1526
+ },
1527
+ "slug": {
1528
+ "type": "string",
1529
+ "description": "SEO-friendly URL segment for the product."
1530
+ },
1531
+ "seller_identifier": {
1532
+ "type": "string",
1533
+ "description": "Unique identifier for the seller of the product."
1534
+ },
1535
+ "brand_id": {
1536
+ "type": "number",
1537
+ "description": "Unique identifier of the brand associated with the product."
1538
+ },
1539
+ "mrp": {
1540
+ "type": "number",
1541
+ "description": "Maximum Retail Price of the product."
1542
+ },
1543
+ "selling_price": {
1544
+ "type": "number",
1545
+ "description": "Selling price of the product."
1546
+ }
1547
+ },
1548
+ "required": ["name", "company_id", "slug", "seller_identifier", "brand_id"]
1549
+ }
1550
+ }
1551
+ },
1552
+ {
1553
+ "type": "function",
1554
+ "function": {
1555
+ "name": "createInventory",
1556
+ "description": "Creates a new inventory record for a specific product in a company.",
1557
+ "parameters": {
1558
+ "type": "object",
1559
+ "properties": {
1560
+ "company_id": {
1561
+ "type": "number",
1562
+ "description": "Unique identifier of the company."
1563
+ },
1564
+ "product_id": {
1565
+ "type": "number",
1566
+ "description": "Unique identifier of the product."
1567
+ },
1568
+ "seller_identifier": {
1569
+ "type": "string",
1570
+ "description": "Unique identifier for the seller of the product."
1571
+ },
1572
+ "location_id": {
1573
+ "type": "number",
1574
+ "description": "Unique identifier of the location where the inventory is stored."
1575
+ },
1576
+ "mrp": {
1577
+ "type": "number",
1578
+ "description": "Maximum Retail Price of the product."
1579
+ },
1580
+ "selling_price": {
1581
+ "type": "number",
1582
+ "description": "Selling price of the product."
1583
+ }
1584
+ },
1585
+ "required": ["company_id", "product_id", "seller_identifier", "location_id"]
1586
+ }
1587
+ }
1588
+ },
1589
+ {
1590
+ "type": "function",
1591
+ "function": {
1592
+ "name": "createApplication",
1593
+ "description": "Creates a new application for a specified company.",
1594
+ "parameters": {
1595
+ "type": "object",
1596
+ "properties": {
1597
+ "company_id": {
1598
+ "type": "number",
1599
+ "description": "Unique identifier of the company."
1600
+ },
1601
+ "brand_ids": {
1602
+ "type": "array",
1603
+ "description": "Array of brand IDs associated with the application.",
1604
+ "items": {
1605
+ "type": "number"
1606
+ }
1607
+ },
1608
+ "name": {
1609
+ "type": "string",
1610
+ "description": "Name of the new application."
1611
+ },
1612
+ "subdomain": {
1613
+ "type": "string",
1614
+ "description": "Subdomain for the application's URL."
1615
+ }
1616
+ },
1617
+ "required": ["company_id", "brand_ids", "name", "subdomain"]
1618
+ }
1619
+ }
1620
+ }
1621
+ ];
1622
+
1623
+ const messages = [{
1624
+ role: 'system',
1625
+ content: 'You are Jio Copilot. Introducing an all-encompassing tool, designed to seamlessly interact with TiraBeauty, JioCinema, JioMart, and JioFiber, catering to multiple facets of your digital lifestyle.\nOur JioMart integration simplifies your online shopping journey, providing a wide selection of products, from clothing and electronics to grocery items, all in one convenient location. JioMart can help to buy ingredients from recipes. Search each ingredient separately.\nWith TiraBeauty functionality, you can explore a wide array of health and beauty products, effortlessly manage your shopping cart, and share your cart selections via a QR code within the ecosystem of www.tirabeauty.com - your comprehensive ecommerce destination for beauty products and accessories.\nThe JioCinema feature takes you on an immersive streaming adventure, offering access to a diverse range of television shows, movies, sports content, and much more. Easily search and stream content to match your mood, directly from this interface.\nFinally, the JioFiber functionality empowers you to navigate through a range of lightning-fast internet and data plans from this leading broadband service provider. Explore and choose from a comprehensive list of prepaid and postpaid plans to meet your connectivity needs.\nEquip yourself with this multifunctional tool and experience a streamlined, efficient digital experience across a variety of platforms.'
1626
+ }];
1627
+ const session = req.jio_copilot_anonymous_session;
1628
+ if (session) {
1629
+ messages.push(...(await listCache.getAll(session)));
1630
+ }
1631
+
1632
+ const userMessage = { role: 'user', content: req.body.prompt };
1633
+ messages.push(userMessage);
1634
+ await listCache.setItems(session, userMessage);
1635
+
1636
+ res.setHeader('Cache-Control', 'no-cache');
1637
+ res.setHeader('Content-Type', 'text/event-stream');
1638
+ // res.setHeader('Access-Control-Allow-Origin', http://);
1639
+ res.setHeader('Connection', 'keep-alive');
1640
+ res.flushHeaders();
1641
+
1642
+ try {
1643
+ // await nextStep(session, messages, skills, functions, res);
1644
+ res.end();
1645
+ } catch (error) {
1646
+ if (error.code === 'context_length_exceeded') {
1647
+ res.write('You have exhausted the conversation limit, clear history and start again!');
1648
+ res.end();
1649
+ }
1650
+ res.write('There is some issue is going on. Please try again later.');
1651
+ res.end();
1652
+ }
1653
+ });
1654
+
1655
+
1656
+ app.use(errorHandler)
1657
+
1658
+ app.listen(port, async () => {
1659
+ console.log(`Example app listening at http://localhost:${port}`);
1660
+ const swaggerSpec = swaggerJSDoc(options);
1661
+
1662
+ // Convert to YAML
1663
+ const swaggerYAML = yaml.dump(swaggerSpec);
1664
+ await fs.writeFileSync("swagger.yaml", swaggerYAML, 'utf-8')
1665
+ await fs.writeFileSync("swagger.json", JSON.stringify(swaggerSpec, null, 2), 'utf-8')
1666
+ });
1667
+
1668
+ // async function nextStep(session, messages, skills, functions, res) {
1669
+ // const conn = new OpenAI({ apiKey: "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" });
1670
+ // const streamResponse = await conn
1671
+ // .chat.completions.create({
1672
+ // model: 'gpt-4-1106-preview',
1673
+ // messages,
1674
+ // functions,
1675
+ // function_call: 'auto',
1676
+ // temperature: 0.5,
1677
+ // stream: true
1678
+ // }).catch(async err => {
1679
+ // console.error(err);
1680
+ // const openAIError = new Error(err.error.message);
1681
+ // openAIError.code = err.error.code;
1682
+ // throw openAIError;
1683
+ // });
1684
+
1685
+ // let finalMessage = '';
1686
+ // const functionCall = { name: null, arguments: '' };
1687
+
1688
+ // for await (const line of streamResponse) {
1689
+ // const choice = line.choices[0];
1690
+ // if (choice.delta.function_call) {
1691
+ // const fc = choice.delta.function_call;
1692
+ // if (fc.name) {
1693
+ // // res.write(`Detected Function: ${fc.name}\n\n`);
1694
+ // // res.flush();
1695
+ // functionCall.name = fc.name;
1696
+ // }
1697
+ // if (fc.arguments) {
1698
+ // functionCall.arguments += fc.arguments;
1699
+ // }
1700
+ // } else if (!choice.finish_reason && choice.delta.content) {
1701
+ // finalMessage += choice.delta.content;
1702
+ // res.write(`${choice.delta.content}`);
1703
+ // res.flush();
1704
+ // }
1705
+ // }
1706
+
1707
+ // if (!functionCall.name) {
1708
+ // const assistantMessage = { role: 'assistant', content: finalMessage };
1709
+ // messages.push(assistantMessage);
1710
+ // await listCache.setItems(session, assistantMessage);
1711
+ // return;
1712
+ // }
1713
+
1714
+ // const functionName = functionCall.name;
1715
+ // const args = JSON.parse(functionCall.arguments);
1716
+ // if (!skills[functionName]) {
1717
+ // throw new Error(`No skill implemented for this function: ${functionName}`);
1718
+ // }
1719
+
1720
+ // // res.write(`Executing Function: ${functionName} with arguments ${JSON.stringify(args)} \n\n`);
1721
+ // // res.flush();
1722
+ // const skill = new skills[functionName]({ ...args, headers: { 'openai-ephemeral-user-id': session } });
1723
+ // const skillRes = await skill.performAction();
1724
+ // if (skillRes) {
1725
+ // const functionMessage = { role: 'function', name: functionName, content: JSON.stringify(skillRes) };
1726
+ // messages.push(functionMessage);
1727
+ // await listCache.setItems(session, functionMessage);
1728
+ // }
1729
+ // return nextStep(conn, session, messages, skills, functions, res);
1730
+ // }
cache.js ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ /**
3
+ * A simple in-memory cache implementation
4
+ */
5
+
6
+ import { Redis } from 'ioredis';
7
+
8
+ export class RedisListCache {
9
+ constructor(params = {}) {
10
+ this.redis = new Redis()
11
+ this.namespace = params.namespace ? params.namespace + ':' : '';
12
+ }
13
+
14
+ // Get a value from the list
15
+ async getItem(key, index) {
16
+ const namespacedKey = this.namespace + key;
17
+ const item = await this.redis.lindex(namespacedKey, index);
18
+ return item ? JSON.parse(item) : null;
19
+ }
20
+
21
+ // Get a value from the list
22
+ async updateItem(key, index, newValue) {
23
+ const namespacedKey = this.namespace + key;
24
+ const length = await this.redis.llen(namespacedKey);
25
+ if (index >= length) {
26
+ throw new Error('Index out of range');
27
+ }
28
+
29
+ // Update the item at the specified index
30
+ await this.redis.lset(namespacedKey, index, JSON.stringify(newValue));
31
+ }
32
+
33
+ // Get a all keys
34
+ async keys(key) {
35
+ const namespacedKey = this.namespace + key;
36
+ return this.redis.keys(namespacedKey);
37
+ }
38
+
39
+ // check if key exists
40
+ async exists(key, index) {
41
+ const namespacedKey = this.namespace + key;
42
+ const item = await this.redis.exists(namespacedKey);
43
+ return item;
44
+ }
45
+
46
+ // Set multiple values in the list
47
+ async setItems(key, ...values) {
48
+ const namespacedKey = this.namespace + key;
49
+ const items = values.map(value => JSON.stringify({
50
+ ...value,
51
+ createdAt: new Date().toISOString()
52
+ }));
53
+ await this.redis.rpush(namespacedKey, ...items);
54
+ }
55
+
56
+ // Remove a value from the list
57
+ async removeItem(key, count, value) {
58
+ const namespacedKey = this.namespace + key;
59
+ const item = JSON.stringify(value);
60
+ return this.redis.lrem(namespacedKey, count, item);
61
+ }
62
+
63
+ // Get the length of the list
64
+ async length(key) {
65
+ const namespacedKey = this.namespace + key;
66
+ return this.redis.llen(namespacedKey);
67
+ }
68
+
69
+ // Get all items from the list
70
+ async getAll(key, page, limit) {
71
+ const namespacedKey = this.namespace + key;
72
+ const items = await this.redis.lrange(namespacedKey, 0, -1);
73
+ if (page && limit) {
74
+ const startIndex = (page - 1) * limit;
75
+ const endIndex = startIndex + limit;
76
+ const _items = items.slice(startIndex, endIndex);
77
+ return _items.map(item => JSON.parse(item));
78
+ }
79
+ return items.map(item => JSON.parse(item));
80
+ }
81
+
82
+ // Remove all items from the list
83
+ async clear(key) {
84
+ const namespacedKey = this.namespace + key;
85
+ return this.redis.del(namespacedKey);
86
+ }
87
+
88
+ // Close the Redis connection
89
+ async close() {
90
+ await this.redis.quit();
91
+ }
92
+ }
chat.html ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <title>Onboarder</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <!-- Meta description -->
8
+ <meta name="description"
9
+ content="Experience the seamless interaction with your digital lifestyle needs using Jio Copilot. From shopping with JioMart, exploring health and beauty products with TiraBeauty, streaming content with JioCinema, to navigating internet plans with JioFiber, Jio Copilot caters to all. Enjoy a streamlined, efficient digital experience across multiple platforms." />
10
+
11
+ <!-- Open Graph -->
12
+ <meta property="og:type" content="website" />
13
+ <meta property="og:url" content="https://jio.copilot.live/" />
14
+ <meta property="og:title" content="Jio CoPilot" />
15
+ <meta property="og:description"
16
+ content="Experience the seamless interaction with your digital lifestyle needs using Jio Copilot. From shopping with JioMart, exploring health and beauty products with TiraBeauty, streaming content with JioCinema, to navigating internet plans with JioFiber, Jio Copilot caters to all. Enjoy a streamlined, efficient digital experience across multiple platforms." />
17
+ <meta property="og:image" content="https://cdn.copilot.live/v2/original/icons/JioGPT_icon.png" />
18
+
19
+ <link rel="stylesheet"
20
+ href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/4.0.0/github-markdown.min.css" />
21
+ <link rel="icon" href="https://cdn.copilot.live/v2/original/icons/JioGPT_icon.png" type="image/x-icon" />
22
+
23
+ <style>
24
+ body {
25
+ display: flex;
26
+ justify-content: center;
27
+ align-items: center;
28
+ height: 100vh;
29
+ margin: 0;
30
+ background-color: white;
31
+ font-family: Arial, sans-serif;
32
+ }
33
+
34
+ #title-bar {
35
+ font-size: 20px;
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: center;
39
+ margin: 12px 0px;
40
+ }
41
+
42
+ #chat-container {
43
+ width: 95%;
44
+ height: 100%;
45
+ max-width: 800px;
46
+ overflow: hidden;
47
+ display: flex;
48
+ flex-direction: column;
49
+ justify-content: space-between;
50
+ }
51
+
52
+ #chat {
53
+ height: calc(100vh - 160px);
54
+ overflow: auto;
55
+ border-radius: 10px;
56
+ }
57
+
58
+ .message {
59
+ padding: 10px;
60
+ margin-bottom: 10px;
61
+ border-radius: 10px;
62
+ }
63
+
64
+ .user {
65
+ align-self: flex-end;
66
+ background-color: #f4a91e;
67
+ color: white;
68
+ display: flex;
69
+ align-items: flex-start;
70
+ justify-content: unset;
71
+ gap: 13px;
72
+ }
73
+
74
+ .ai {
75
+ align-self: flex-start;
76
+ background-color: #eee;
77
+ color: black;
78
+ display: flex;
79
+ align-items: flex-start;
80
+ justify-content: unset;
81
+ gap: 13px;
82
+ }
83
+
84
+ #input-container {
85
+ display: flex;
86
+ height: 70px;
87
+ border-radius: 10px;
88
+ margin-bottom: 10px;
89
+ }
90
+
91
+ #message {
92
+ width: 80%;
93
+ border: 0;
94
+ font-size: 16px;
95
+ padding: 10px;
96
+ border-radius: 10px 0 0 10px;
97
+ background-color: #eee;
98
+ }
99
+
100
+ #message:focus-visible {
101
+ outline: 0;
102
+ }
103
+
104
+ #send {
105
+ width: 20%;
106
+ max-width: 200px;
107
+ background-color: #3635f0;
108
+ color: white;
109
+ border: none;
110
+ font-size: 16px;
111
+ cursor: pointer;
112
+ }
113
+
114
+ #clear-history {
115
+ width: 80px;
116
+ font-size: 16px;
117
+ border: none;
118
+ color: white;
119
+ background-color: #1ecbae;
120
+ border-radius: 0 10px 10px 0;
121
+ cursor: pointer;
122
+ }
123
+
124
+ .disable-button {
125
+ background-color: #eee !important;
126
+ cursor: not-allowed !important;
127
+ color: #c3c3c3 !important;
128
+ }
129
+
130
+ .cursor {
131
+ height: 1.2em;
132
+ width: 0.7em;
133
+ background-color: #374151;
134
+ animation: blink 1s infinite;
135
+ }
136
+
137
+ /* Animation */
138
+ @keyframes blink {
139
+ 0% {
140
+ opacity: 1;
141
+ }
142
+
143
+ 50% {
144
+ opacity: 0;
145
+ }
146
+
147
+ 100% {
148
+ opacity: 1;
149
+ }
150
+ }
151
+ </style>
152
+ </head>
153
+
154
+ <body>
155
+ <div id="chat-container">
156
+ <div id="title-bar">
157
+ <img src="https://cdn.copilot.live/v2/original/icons/JioGPT_icon.png" width="40px" height="40px" />
158
+ Jio CoPilot
159
+ </div>
160
+ <div id="chat"></div>
161
+ <div id="input-container">
162
+ <input id="message" type="text" placeholder="Type your message" />
163
+ <button id="send" title="Send Message">Send</button>
164
+ <button id="clear-history" title="Clear history">Clear</button>
165
+ </div>
166
+ </div>
167
+
168
+ <!-- Import marked.js for markdown rendering -->
169
+ <script src="https://cdn.jsdelivr.net/npm/marked@5.1.0/marked.min.js"></script>
170
+
171
+ <script>
172
+ const renderer = new marked.Renderer();
173
+ const linkRenderer = renderer.link;
174
+ renderer.link = (href, title, text) => {
175
+ const html = linkRenderer.call(renderer, href, title, text);
176
+ return html.replace(
177
+ /^<a /,
178
+ '<a target="_blank" rel="noopener noreferrer" '
179
+ );
180
+ };
181
+ marked.setOptions({ renderer });
182
+
183
+ class StateManager {
184
+ constructor(initialState = {}) {
185
+ this.state = initialState;
186
+ this.listeners = [];
187
+ }
188
+ getState() {
189
+ return this.state;
190
+ }
191
+ subscribe(listener) {
192
+ this.listeners.push(listener);
193
+ }
194
+ updateState(newState) {
195
+ this.state = { ...this.state, ...newState };
196
+ this.listeners.forEach((listener) => listener(this.state));
197
+ }
198
+ }
199
+ const stateManager = new StateManager({ inprogress: false });
200
+
201
+ const chatElement = document.getElementById("chat");
202
+ document.addEventListener("DOMContentLoaded", (event) => {
203
+ const messageElement = document.querySelector("#message");
204
+ const sendButton = document.querySelector("#send");
205
+ const clearButton = document.querySelector("#clear-history");
206
+
207
+ sendButton.addEventListener("click", sendMessage);
208
+ messageElement.addEventListener("keydown", (event) => {
209
+ if (event.key === "Enter") {
210
+ const inprogress = stateManager.getState().inprogress;
211
+ if (!inprogress) {
212
+ sendMessage();
213
+ }
214
+ }
215
+ });
216
+ clearButton.addEventListener("click", clearHistory);
217
+
218
+ loadChatHistory();
219
+ });
220
+
221
+ async function loadChatHistory() {
222
+ const response = await fetch("/v1/talk/history", { method: "GET" });
223
+
224
+ if (!response.ok) {
225
+ console.error("Failed to fetch chat history");
226
+ return;
227
+ }
228
+
229
+ const chatHistory = await response.json();
230
+
231
+ for (const message of chatHistory) {
232
+ appendMessage(
233
+ message.content,
234
+ message.role === "user" ? "user" : "ai"
235
+ );
236
+ }
237
+ }
238
+
239
+ async function clearHistory() {
240
+ const response = await fetch("/v1/talk/history", { method: "DELETE" });
241
+
242
+ if (response.ok) {
243
+ chatElement.replaceChildren(chatElement.firstChild);
244
+
245
+ stateManager.updateState({ inprogress: false });
246
+ } else {
247
+ console.error("Failed to clear chat history");
248
+ }
249
+ }
250
+
251
+ async function sendMessage() {
252
+ const messageElement = document.querySelector("#message");
253
+ const message = messageElement.value;
254
+ messageElement.value = "";
255
+ appendMessage(message, "user");
256
+ const aiMessageContainer = appendMessage("", "ai");
257
+ const aiMessageElement = aiMessageContainer.childNodes[1];
258
+ const sendButton = document.getElementById("send");
259
+ sendButton.disabled = true;
260
+ sendButton.classList.add("disable-button");
261
+ const cursor = document.createElement("div");
262
+ cursor.classList.add("cursor");
263
+ aiMessageElement.appendChild(cursor)
264
+ const response = await fetch("/openai", {
265
+ method: "POST",
266
+ headers: { "Content-Type": "application/json" },
267
+ body: JSON.stringify({ prompt: message }),
268
+ });
269
+
270
+ const reader = response.body
271
+ .pipeThrough(new TextDecoderStream())
272
+ .getReader();
273
+ let serverMessage = "";
274
+ let count = 0;
275
+ while (true) {
276
+ stateManager.updateState({ inprogress: true });
277
+ const { value, done } = await reader.read();
278
+ if (done) {
279
+ stateManager.updateState({ inprogress: false });
280
+ document.getElementById("send").disabled = false;
281
+ sendButton.disabled = false;
282
+ sendButton.classList.remove("disable-button");
283
+ break;
284
+ }
285
+ serverMessage += value;
286
+ aiMessageElement.innerHTML = marked.parse(
287
+ serverMessage.replace(/\\n/g, "<br>"),
288
+ { breaks: true }
289
+ );
290
+ if (
291
+ count % 10 == 0 &&
292
+ chatElement.scrollHeight -
293
+ chatElement.scrollTop -
294
+ chatElement.clientHeight <=
295
+ 44
296
+ ) {
297
+ aiMessageElement.scrollIntoView();
298
+ }
299
+ count++;
300
+ }
301
+ chatElement.scrollTop = chatElement.scrollHeight;
302
+ }
303
+
304
+ function appendMessage(message, sender) {
305
+ const div = document.createElement("div");
306
+ div.classList.add("message", "markdown-body", sender);
307
+ div.appendChild(createIcon(sender));
308
+ div.appendChild(createTextElement(message, sender));
309
+ chatElement.appendChild(div);
310
+ div.scrollIntoView();
311
+ chatElement.scrollTop = chatElement.scrollHeight;
312
+ return div;
313
+ }
314
+
315
+ function createIcon(sender) {
316
+ const icon = document.createElement("img");
317
+ icon.style.width = "40px";
318
+ icon.style.height = "40px";
319
+ icon.style.marginTop = "10px";
320
+ icon.style.backgroundColor = "unset";
321
+ icon.alt = sender.charAt(0).toUpperCase() + sender.slice(1) + " Icon";
322
+ icon.src =
323
+ sender === "ai"
324
+ ? "https://cdn.copilot.live/v2/original/icons/JioGPT_icon.png"
325
+ : "https://img.icons8.com/?size=512&id=108296&format=png";
326
+ return icon;
327
+ }
328
+
329
+ function createTextElement(message, sender) {
330
+ const textElement = document.createElement("div");
331
+ textElement.innerHTML = marked.parse(message, { breaks: true });
332
+ return textElement;
333
+ }
334
+ </script>
335
+ </body>
336
+
337
+ </html>
functions.js ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Redis from "ioredis";
2
+ import { initClient } from './utils.js';
3
+
4
+ const redis = new Redis();
5
+
6
+
7
+
8
+ export const getCompanyCreds = async ({ company_id }) => {
9
+ const creds = await redis.get(`${companyId}:creds`);
10
+ if (!creds) {
11
+ throw {
12
+ message: "company creds not found"
13
+ }
14
+ }
15
+ return { ...JSON.parse(creds), company_id }
16
+ }
17
+ export const createUpdateCompanyCreds = async ({ company_id, clientId, clientSecret }) => {
18
+ const creds = await redis.set(`${company_id}:creds`, JSON.stringify({ clientId, clientSecret }));
19
+ return { message: "company creds saved" }
20
+ }
21
+ export const getApplications = async ({ company_id }) => {
22
+ const client = await initClient(company_id);
23
+ let applications = await client.configuration.getApplications({ pageSize: 100 });
24
+ applications = applications.items.map(i => {
25
+ return {
26
+ name: i.name,
27
+ id: i.id,
28
+ token: i.token,
29
+ domain: i.domains?.find(i => i.is_primary)?.name,
30
+ logo: i.logo?.secure_url
31
+ }
32
+ })
33
+ return applications;
34
+ }
35
+ export const createBrand = async ({ company_id, name, description, logo = "https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/fyprod/wrkr/platform/pictures/favicon/original/ZWTmgEoFQ-platform-favicon.png" }) => {
36
+ const client = await initClient(company_id);
37
+ let brands = await client.companyProfile.createBrand({
38
+ body: {
39
+ name,
40
+ description,
41
+ logo,
42
+ banner: { portrait: logo, landscape: logo }
43
+ }
44
+ });
45
+ return { message: "brand created", id: brands?.id };
46
+ }
47
+ export const getBrands = async ({ company_id }) => {
48
+ const client = await initClient(company_id);
49
+ let brands = await client.companyProfile.getBrands({ pageSize: 300 });
50
+ brands = brands.items.map(i => {
51
+ return {
52
+ name: i?.brand?.name,
53
+ logo: i?.brand?.logo,
54
+ id: i?.brand?.uid,
55
+ }
56
+ })
57
+ return brands
58
+ }
59
+ export const updateBrand = async ({ company_id, brand_id }) => {
60
+ const client = await initClient(company_id);
61
+ let brands = await client.companyProfile.editBrand({
62
+ brand_id,
63
+ body: {
64
+ name,
65
+ description,
66
+ logo,
67
+ banner: { portrait: logo, landscape: logo }
68
+ }
69
+ });
70
+ return { message: "brand updated" }
71
+ }
72
+
73
+ export const getLocations = async ({ company_id }) => {
74
+ const client = await initClient(company_id);
75
+ let locations = await client.companyProfile.getLocations({ pageSize: 100 });
76
+ locations = locations.items.map(i => {
77
+ return {
78
+ name: i.name,
79
+ id: i.uid,
80
+ code: i.code,
81
+ documents: i.documents
82
+ }
83
+ })
84
+ return locations;
85
+ }
86
+ export const createLocation = async ({ company_id, address1, address2, pincode, state, city, number, country_code, gst_name, gst_no, latitude = 19.2762702, longitude = 72.8929, }) => {
87
+ const client = await initClient(company_id);
88
+ let locations = await client.companyProfile.createLocation({
89
+ body: {
90
+ name,
91
+ display_name: name,
92
+ code,
93
+ company: parseInt(companyId),
94
+ documents: [{
95
+ type: "gst",
96
+ legal_name: gst_name,
97
+ value: gst_no,
98
+ verified: true
99
+ }],
100
+ address: {
101
+ "address1": address1,
102
+ "address2": address2,
103
+ "country": country,
104
+ "pincode": pincode,
105
+ "city": city,
106
+ "state": state,
107
+ "latitude": latitude,
108
+ "longitude": longitude,
109
+ "landmark": landmark
110
+ },
111
+ manager: {
112
+ "name": manager_name,
113
+ "email": email,
114
+ "mobile_no": {
115
+ "number": number,
116
+ "country_code": country_code
117
+ }
118
+ },
119
+ contact_numbers: [
120
+ {
121
+ "number": number,
122
+ "country_code": country_code
123
+ }
124
+ ],
125
+ store_type: "high_street"
126
+
127
+ }
128
+ });
129
+
130
+ return { message: "location added", id: locations?.id };
131
+ }
132
+ export const updateLocation = async ({ company_id, location_id, address1, address2, pincode, state, city, number, country_code, gst_name, gst_no, latitude = 19.2762702, longitude = 72.8929,
133
+ }) => {
134
+ const client = await initClient(company_id);
135
+ let locations = await client.companyProfile.updateLocation({
136
+ locationId: location_id,
137
+ body: {
138
+ name,
139
+ display_name: name,
140
+ code,
141
+ company: parseInt(companyId),
142
+ documents: [{
143
+ type: "gst",
144
+ legal_name: gst_name,
145
+ value: gst_no,
146
+ verified: true
147
+ }],
148
+ address: {
149
+ "address1": address1,
150
+ "address2": address2,
151
+ "country": country,
152
+ "pincode": pincode,
153
+ "city": city,
154
+ "state": state,
155
+ "latitude": latitude,
156
+ "longitude": longitude,
157
+ "landmark": landmark
158
+ },
159
+ manager: {
160
+ "name": manager_name,
161
+ "email": email,
162
+ "mobile_no": {
163
+ "number": number,
164
+ "country_code": country_code
165
+ }
166
+ },
167
+ contact_numbers: [
168
+ {
169
+ "number": number,
170
+ "country_code": country_code
171
+ }
172
+ ],
173
+ store_type: "high_street"
174
+
175
+ }
176
+ });
177
+
178
+ return { message: "location updated" };
179
+ }
180
+ export const createApplication = async ({ company_id, brand_ids, name, subdomain }) => {
181
+ const client = await initClient(company_id);
182
+ let app = await client.configuration.createApplication({
183
+ body: {
184
+ "app": {
185
+ "company_id": (1).toString(),
186
+ "channel_type": "website-and-mobile-apps",
187
+ "auth": {
188
+ "enabled": true
189
+ },
190
+ "name": name,
191
+ "desc": "",
192
+ "mode": "live"
193
+ },
194
+ "configuration": {
195
+ "inventory": {
196
+ "brand": {
197
+ "criteria": "all",
198
+ "brands": []
199
+ },
200
+ "store": {
201
+ "criteria": "filter",
202
+ "rules": [
203
+ {
204
+ "companies": [company_id],
205
+ "brands": brand_ids
206
+ }
207
+ ],
208
+ "stores": []
209
+ },
210
+ "image": ["standard", "substandard", "default"],
211
+ "franchise_enabled": false,
212
+ "out_of_stock": true
213
+ },
214
+ "payment": {
215
+ "mode_of_payment": "ECOMM",
216
+ "source": "ECOMM"
217
+ },
218
+ "article_assignment": {
219
+ "post_order_reassignment": true,
220
+ "enforced_stores": [],
221
+ "rules": {
222
+ "store_priority": {
223
+ "enabled": false,
224
+ "storetype_order": []
225
+ }
226
+ }
227
+ }
228
+ },
229
+ "domain": {
230
+ "name": `${subdomain}.hostx5.de`
231
+ }
232
+ }
233
+ })
234
+
235
+
236
+ return { message: "location updated" };
237
+ }
238
+ export const createProduct = async ({ name, company_id, slug,
239
+ seller_identifier,
240
+ brand_id, mrp = 999, selling_price = 499 }) => {
241
+ const client = await initClient(company_id);
242
+ const obj = {
243
+ "name": name,
244
+ "slug": slug,
245
+ "brand_uid": brand_id,
246
+ "item_code": seller_identifier,
247
+ "teaser_tag": {},
248
+ "net_quantity": {},
249
+ "tax_identifier": {
250
+ "reporting_hsn": "1202355241H1",
251
+ "hsn_code": "1202355241",
252
+ "hsn_code_id": "65769883ba99dcf407a2b1ed"
253
+ },
254
+ "country_of_origin": "India",
255
+ "variants": {},
256
+ "variant_media": {},
257
+ "description": "PHA+WW91ciBwcm9kdWN0IGRlc2NyaXB0aW9uPC9wPg==",
258
+ "short_description": "Your product description",
259
+ "highlights": [],
260
+ "company_id": 10,
261
+ "template_tag": "c2-0-template",
262
+ "currency": "INR",
263
+ "media": [],
264
+ "is_set": false,
265
+ "sizes": [
266
+ {
267
+ "size": "OS",
268
+ "price": mrp,
269
+ "price_effective": selling_price,
270
+ "price_transfer": 0,
271
+ "currency": "INR",
272
+ "item_length": 1,
273
+ "item_width": 1,
274
+ "item_height": 1,
275
+ "item_weight": 1,
276
+ "item_dimensions_unit_of_measure": "cm",
277
+ "item_weight_unit_of_measure": "gram",
278
+ "track_inventory": true,
279
+ "identifiers": [
280
+ {
281
+ "gtin_value": seller_identifier,
282
+ "gtin_type": "ean",
283
+ "primary": true
284
+ }
285
+ ],
286
+ "_custom_json": {},
287
+ "name": "OS"
288
+ }
289
+ ],
290
+ "_custom_json": {},
291
+ "size_guide": "",
292
+ "product_group_tag": [],
293
+ "product_publish": {
294
+ "product_online_date": "2023-12-11T08:38:10.082Z",
295
+ "is_set": false
296
+ },
297
+ "is_active": true,
298
+ "custom_order": {
299
+ "is_custom_order": false,
300
+ "manufacturing_time": 0,
301
+ "manufacturing_time_unit": "hours"
302
+ },
303
+ "multi_size": false,
304
+ "no_of_boxes": 1,
305
+ "is_dependent": false,
306
+ "item_type": "digital",
307
+ "tags": [],
308
+ "departments": [
309
+ 19771
310
+ ],
311
+ return_config: {
312
+ "returnable": false
313
+ },
314
+ "category_slug": "c2-0-cat",
315
+ "trader": [
316
+ {
317
+ "type": "Manufacturer",
318
+ "name": "Manufacturer",
319
+ "address": [
320
+ "Manufacturer Address"
321
+ ]
322
+ }
323
+ ],
324
+ "return_config": {
325
+ "returnable": true,
326
+ time: 3,
327
+ unit: "days"
328
+ }
329
+ }
330
+ let product = await client.catalog.createProduct({
331
+ body: obj
332
+ });
333
+ product = await client.catalog.getProduct({
334
+ itemId: product.uid
335
+ });
336
+ return {
337
+ message: "product created",
338
+ id: product.data.uid,
339
+ seller_identifier: product?.data?.sizes?.[0]?.seller_identifier
340
+ };
341
+ }
342
+ export const createInventory = async ({ company_id, product_id, seller_identifier, location_id, mrp = 999, selling_price = 499 }) => {
343
+ const client = await initClient(company_id);
344
+ let product = await client.catalog.getProduct({
345
+ itemId: product_id
346
+ });
347
+ let inv = await client.catalog.updateRealtimeInventory({
348
+ itemId: product.data.uid,
349
+ sellerIdentifier: seller_identifier,
350
+ body: {
351
+ company_id: company_id,
352
+ payload: [{
353
+ "seller_identifier": seller_identifier,
354
+ "store_id": location_id,
355
+ "price_marked": mrp,
356
+ "price_effective": selling_price,
357
+ "total_quantity": 10,
358
+ "tags": []
359
+ }]
360
+ }
361
+ })
362
+
363
+ return { message: "inv created" };
364
+ }
index.js CHANGED
@@ -5,7 +5,8 @@ import { errorHandler } from './middleware.js';
5
  import swaggerJSDoc from 'swagger-jsdoc';
6
  import yaml from 'js-yaml'
7
  import fs from 'fs';
8
-
 
9
  const redis = new Redis();
10
 
11
  const app = express();
@@ -450,7 +451,7 @@ app.get("/company/:companyId/brands", async (req, res, next) => {
450
  * name: brandId
451
  * required: true
452
  * schema:
453
- * type: string
454
  * description: The unique identifier of the brand
455
  * requestBody:
456
  * required: true
@@ -577,7 +578,7 @@ app.put("/company/:companyId/brands/:brandId", async (req, res, next) => {
577
  app.get("/company/:companyId/locations", async (req, res, next) => {
578
  try {
579
  const { companyId } = req.params;
580
- const client = await initClient(companyId);
581
  let locations = await client.companyProfile.getLocations({ pageSize: 100 });
582
  locations = locations.items.map(i => {
583
  return {
@@ -820,111 +821,838 @@ app.put("/company/:companyId/locations/locationId", async (req, res, next) => {
820
  }
821
  })
822
 
 
 
823
  /**
824
  * @swagger
825
- * /company/{companyId}/departments:
826
- * get:
827
- * summary: Retrieve departments for a specific company
828
- * description: Fetches a list of departments associated with the given company ID.
829
- * tags: [Company]
830
- * operationId: getCompanyDepartments
 
831
  * parameters:
832
  * - in: path
833
  * name: companyId
834
  * required: true
835
  * schema:
836
  * type: string
837
- * description: The unique identifier of the company
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
838
  * responses:
839
  * 200:
840
- * description: An array of department objects
841
  * content:
842
  * application/json:
843
  * schema:
844
- * type: array
845
- * items:
846
- * type: object
847
- * properties:
848
- * name:
849
- * type: string
850
- * description: Name of the department
851
- * slug:
852
- * type: string
853
- * description: slug or identifier of the department
854
  */
855
 
856
- app.get("/company/:companyId/departments", async (req, res, next) => {
857
  try {
858
  const { companyId } = req.params;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
859
  const client = await initClient(companyId);
860
- let departments = await client.catalog.listDepartmentsData({
861
- isActive: true, pageSize: 100, pageNo: 1
 
 
 
 
 
 
 
 
862
  });
863
- departments = departments?.items?.map(i => { return { name: i.name, slug: i.slug } })
864
- res.json(departments);
865
-
866
  } catch (e) { next(e) }
867
  })
 
868
  /**
869
  * @swagger
870
- * /company/{companyId}/departments/{departmentSlug}:
871
- * get:
872
- * summary: Retrieve categories for a specific department
873
- * description: Retrieve categories for a specific department.
874
- * tags: [Company]
875
- * operationId: getDepartmentCategories
 
876
  * parameters:
877
  * - in: path
878
  * name: companyId
879
  * required: true
880
  * schema:
881
  * type: string
882
- * description: The unique identifier of the company
883
- * parameters:
884
  * - in: path
885
- * name: dea
886
  * required: true
887
  * schema:
888
  * type: string
889
- * description: The unique identifier of the company
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
890
  * parameters:
891
- * - in: query
892
  * name: companyId
893
  * required: true
894
  * schema:
895
  * type: string
896
- * description: The unique identifier of the company
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
897
  * responses:
898
  * 200:
899
- * description: An array of department objects
900
  * content:
901
  * application/json:
902
  * schema:
903
- * type: array
904
- * items:
905
- * type: object
906
- * properties:
907
- * name:
908
- * type: string
909
- * description: Name of the category
910
- * slug:
911
- * type: string
912
- * description: slug or identifier of the catrgory
 
913
  */
914
- app.get("/company/:companyId/departments/:departmentSlug", async (req, res, next) => {
 
915
  try {
916
- const { companyId, departmentSlug } = req.params;
917
- const { item_type = 'single' } = req.query;
918
  const client = await initClient(companyId);
919
- let categories = await client.catalog.listProductTemplateCategories({
920
- departments: departmentSlug, pageNo: 1, pageSize: 100, itemType: item_type
921
- });
922
- categories = categories?.items?.map(i => { return { name: i.name, slug: i.slug } })
923
- res.json(categories);
924
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
925
  } catch (e) { next(e) }
926
  })
927
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
928
  app.use(errorHandler)
929
 
930
  app.listen(port, async () => {
@@ -936,3 +1664,67 @@ app.listen(port, async () => {
936
  await fs.writeFileSync("swagger.yaml", swaggerYAML, 'utf-8')
937
  await fs.writeFileSync("swagger.json", JSON.stringify(swaggerSpec, null, 2), 'utf-8')
938
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  import swaggerJSDoc from 'swagger-jsdoc';
6
  import yaml from 'js-yaml'
7
  import fs from 'fs';
8
+ import { RedisListCache } from './cache.js';
9
+ const listCache = new RedisListCache({ namespace: "fc" })
10
  const redis = new Redis();
11
 
12
  const app = express();
 
451
  * name: brandId
452
  * required: true
453
  * schema:
454
+ * type: number
455
  * description: The unique identifier of the brand
456
  * requestBody:
457
  * required: true
 
578
  app.get("/company/:companyId/locations", async (req, res, next) => {
579
  try {
580
  const { companyId } = req.params;
581
+ const client = await initClient(companyId.toString());
582
  let locations = await client.companyProfile.getLocations({ pageSize: 100 });
583
  locations = locations.items.map(i => {
584
  return {
 
821
  }
822
  })
823
 
824
+
825
+
826
  /**
827
  * @swagger
828
+ * /company/{companyId}/products:
829
+ * post:
830
+ * summary: Creates a new product for a given company.
831
+ * description: This endpoint creates a new product with various attributes including name, slug, pricing, and more.
832
+ * operationId: createProduct
833
+ * tags:
834
+ * - Products
835
  * parameters:
836
  * - in: path
837
  * name: companyId
838
  * required: true
839
  * schema:
840
  * type: string
841
+ * description: Unique identifier of the company.
842
+ * requestBody:
843
+ * required: true
844
+ * content:
845
+ * application/json:
846
+ * schema:
847
+ * type: object
848
+ * required:
849
+ * - name
850
+ * - slug
851
+ * - seller_identifier
852
+ * - brand_id
853
+ * properties:
854
+ * name:
855
+ * type: string
856
+ * description: Name of the product.
857
+ * slug:
858
+ * type: string
859
+ * description: URL-friendly identifier for the product.
860
+ * seller_identifier:
861
+ * type: string
862
+ * description: Unique identifier for the seller.
863
+ * brand_id:
864
+ * type: string
865
+ * description: Unique identifier for the brand.
866
+ * location_id:
867
+ * type: string
868
+ * description: Location identifier for the product.
869
+ * mrp:
870
+ * type: number
871
+ * default: 999
872
+ * description: Maximum retail price of the product.
873
+ * selling_price:
874
+ * type: number
875
+ * default: 499
876
+ * description: Selling price of the product.
877
  * responses:
878
  * 200:
879
+ * description: Successful creation of the product.
880
  * content:
881
  * application/json:
882
  * schema:
883
+ * type: object
884
+ * properties:
885
+ * message:
886
+ * type: string
887
+ * id:
888
+ * type: string
889
+ * seller_identifier:
890
+ * type: string
 
 
891
  */
892
 
893
+ app.post("/company/:companyId/products", async (req, res, next) => {
894
  try {
895
  const { companyId } = req.params;
896
+ const { name,
897
+ slug,
898
+ seller_identifier,
899
+ brand_id, location_id, mrp = 999, selling_price = 499
900
+ } = req.body;
901
+ const obj = {
902
+ "name": name,
903
+ "slug": slug,
904
+ "brand_uid": brand_id,
905
+ "item_code": seller_identifier,
906
+ "teaser_tag": {},
907
+ "net_quantity": {},
908
+ "tax_identifier": {
909
+ "reporting_hsn": "1202355241H1",
910
+ "hsn_code": "1202355241",
911
+ "hsn_code_id": "65769883ba99dcf407a2b1ed"
912
+ },
913
+ "country_of_origin": "India",
914
+ "variants": {},
915
+ "variant_media": {},
916
+ "description": "PHA+WW91ciBwcm9kdWN0IGRlc2NyaXB0aW9uPC9wPg==",
917
+ "short_description": "Your product description",
918
+ "highlights": [],
919
+ "company_id": 10,
920
+ "template_tag": "c2-0-template",
921
+ "currency": "INR",
922
+ "media": [],
923
+ "is_set": false,
924
+ "sizes": [
925
+ {
926
+ "size": "OS",
927
+ "price": mrp,
928
+ "price_effective": selling_price,
929
+ "price_transfer": 0,
930
+ "currency": "INR",
931
+ "item_length": 1,
932
+ "item_width": 1,
933
+ "item_height": 1,
934
+ "item_weight": 1,
935
+ "item_dimensions_unit_of_measure": "cm",
936
+ "item_weight_unit_of_measure": "gram",
937
+ "track_inventory": true,
938
+ "identifiers": [
939
+ {
940
+ "gtin_value": seller_identifier,
941
+ "gtin_type": "ean",
942
+ "primary": true
943
+ }
944
+ ],
945
+ "_custom_json": {},
946
+ "name": "OS"
947
+ }
948
+ ],
949
+ "_custom_json": {},
950
+ "size_guide": "",
951
+ "product_group_tag": [],
952
+ "product_publish": {
953
+ "product_online_date": "2023-12-11T08:38:10.082Z",
954
+ "is_set": false
955
+ },
956
+ "is_active": true,
957
+ "custom_order": {
958
+ "is_custom_order": false,
959
+ "manufacturing_time": 0,
960
+ "manufacturing_time_unit": "hours"
961
+ },
962
+ "multi_size": false,
963
+ "no_of_boxes": 1,
964
+ "is_dependent": false,
965
+ "item_type": "digital",
966
+ "tags": [],
967
+ "departments": [
968
+ 19771
969
+ ],
970
+ return_config: {
971
+ "returnable": false
972
+ },
973
+ "category_slug": "c2-0-cat",
974
+ "trader": [
975
+ {
976
+ "type": "Manufacturer",
977
+ "name": "Manufacturer",
978
+ "address": [
979
+ "Manufacturer Address"
980
+ ]
981
+ }
982
+ ],
983
+ "return_config": {
984
+ "returnable": true,
985
+ time: 3,
986
+ unit: "days"
987
+ }
988
+ }
989
  const client = await initClient(companyId);
990
+ let product = await client.catalog.createProduct({
991
+ body: obj
992
+ });
993
+ product = await client.catalog.getProduct({
994
+ itemId: product.uid
995
+ });
996
+ res.json({
997
+ message: "product created",
998
+ id: product.data.uid,
999
+ seller_identifier: product?.data?.sizes?.[0]?.seller_identifier
1000
  });
 
 
 
1001
  } catch (e) { next(e) }
1002
  })
1003
+
1004
  /**
1005
  * @swagger
1006
+ * /company/{companyId}/products/{productId}/inventory:
1007
+ * post:
1008
+ * summary: Updates inventory for a specific product.
1009
+ * description: This endpoint updates the inventory details for a given product, including location, pricing, and quantity.
1010
+ * operationId: updateInventory
1011
+ * tags:
1012
+ * - Inventory
1013
  * parameters:
1014
  * - in: path
1015
  * name: companyId
1016
  * required: true
1017
  * schema:
1018
  * type: string
1019
+ * description: Unique identifier of the company.
 
1020
  * - in: path
1021
+ * name: productId
1022
  * required: true
1023
  * schema:
1024
  * type: string
1025
+ * description: Unique identifier of the product.
1026
+ * requestBody:
1027
+ * required: true
1028
+ * content:
1029
+ * application/json:
1030
+ * schema:
1031
+ * type: object
1032
+ * required:
1033
+ * - location_id
1034
+ * - seller_identifier
1035
+ * properties:
1036
+ * location_id:
1037
+ * type: string
1038
+ * description: Location identifier where the inventory is stored.
1039
+ * mrp:
1040
+ * type: number
1041
+ * default: 999
1042
+ * description: Maximum retail price of the product.
1043
+ * selling_price:
1044
+ * type: number
1045
+ * default: 499
1046
+ * description: Selling price of the product.
1047
+ * seller_identifier:
1048
+ * type: string
1049
+ * description: Unique identifier for the seller.
1050
+ * responses:
1051
+ * 200:
1052
+ * description: Successful update of inventory.
1053
+ * content:
1054
+ * application/json:
1055
+ * schema:
1056
+ * type: object
1057
+ * properties:
1058
+ * message:
1059
+ * type: string
1060
+ */
1061
+ app.post("/company/:companyId/products/:productId/inventory", async (req, res, next) => {
1062
+ try {
1063
+ const { companyId, productId } = req.params;
1064
+ const { location_id, mrp = 999, selling_price = 499, id, seller_identifier } = req.body;
1065
+ const client = await initClient(companyId);
1066
+ let product = await client.catalog.getProduct({
1067
+ itemId: productId
1068
+ });
1069
+ let inv = await client.catalog.updateRealtimeInventory({
1070
+ itemId: product.data.uid,
1071
+ sellerIdentifier: seller_identifier,
1072
+ body: {
1073
+ company_id: companyId,
1074
+ payload: [{
1075
+ "seller_identifier": seller_identifier,
1076
+ "store_id": location_id,
1077
+ "price_marked": mrp,
1078
+ "price_effective": selling_price,
1079
+ "total_quantity": 10,
1080
+ "tags": []
1081
+ }]
1082
+ }
1083
+ })
1084
+
1085
+ res.json({ message: "inv created" });
1086
+ } catch (e) { next(e) }
1087
+ })
1088
+
1089
+
1090
+ /**
1091
+ * @swagger
1092
+ * /company/{companyId}/sales_channel:
1093
+ * post:
1094
+ * operationId: addSalesChannel
1095
+ * summary: Create a sales channel for a given company
1096
+ * description: This endpoint creates a new sales channel for the specified company.
1097
+ * tags:
1098
+ * - Sales Channel
1099
  * parameters:
1100
+ * - in: path
1101
  * name: companyId
1102
  * required: true
1103
  * schema:
1104
  * type: string
1105
+ * description: The ID of the company
1106
+ * requestBody:
1107
+ * required: true
1108
+ * content:
1109
+ * application/json:
1110
+ * schema:
1111
+ * type: object
1112
+ * properties:
1113
+ * brand_ids:
1114
+ * type: array
1115
+ * items:
1116
+ * type: integer
1117
+ * description: Array of brand IDs to be associated with the sales channel
1118
+ * name:
1119
+ * type: string
1120
+ * description: Name of the sales channel
1121
+ * subdomain:
1122
+ * type: string
1123
+ * description: subdomain associated with the sales channel
1124
  * responses:
1125
  * 200:
1126
+ * description: Sales channel successfully created
1127
  * content:
1128
  * application/json:
1129
  * schema:
1130
+ * type: object
1131
+ * properties:
1132
+ * message:
1133
+ * type: string
1134
+ * app:
1135
+ * type: object
1136
+ * description: Details of the created sales channel
1137
+ * 400:
1138
+ * description: Bad request
1139
+ * 500:
1140
+ * description: Internal server error
1141
  */
1142
+
1143
+ app.post("/company/:companyId/sales_channel", async (req, res, next) => {
1144
  try {
1145
+ const { companyId } = req.params;
1146
+ const { brand_ids, name, subdomain } = req.body;
1147
  const client = await initClient(companyId);
 
 
 
 
 
1148
 
1149
+ let app = await client.configuration.createApplication({
1150
+ body: {
1151
+ "app": {
1152
+ "company_id": (1).toString(),
1153
+ "channel_type": "website-and-mobile-apps",
1154
+ "auth": {
1155
+ "enabled": true
1156
+ },
1157
+ "name": name,
1158
+ "desc": "",
1159
+ "mode": "live"
1160
+ },
1161
+ "configuration": {
1162
+ "inventory": {
1163
+ "brand": {
1164
+ "criteria": "all",
1165
+ "brands": []
1166
+ },
1167
+ "store": {
1168
+ "criteria": "filter",
1169
+ "rules": [
1170
+ {
1171
+ "companies": [companyId],
1172
+ "brands": brand_ids
1173
+ }
1174
+ ],
1175
+ "stores": []
1176
+ },
1177
+ "image": ["standard", "substandard", "default"],
1178
+ "franchise_enabled": false,
1179
+ "out_of_stock": true
1180
+ },
1181
+ "payment": {
1182
+ "mode_of_payment": "ECOMM",
1183
+ "source": "ECOMM"
1184
+ },
1185
+ "article_assignment": {
1186
+ "post_order_reassignment": true,
1187
+ "enforced_stores": [],
1188
+ "rules": {
1189
+ "store_priority": {
1190
+ "enabled": false,
1191
+ "storetype_order": []
1192
+ }
1193
+ }
1194
+ }
1195
+ },
1196
+ "domain": {
1197
+ "name": `${subdomain}.hostx5.de`
1198
+ }
1199
+ }
1200
+ })
1201
+
1202
+ res.json({ message: "inv created", app });
1203
  } catch (e) { next(e) }
1204
  })
1205
 
1206
+ const chatHtml = fs.readFileSync('./chat.html', 'utf-8');
1207
+
1208
+ app.get('/', async (req, res, next) => {
1209
+ try {
1210
+ res.send(chatHtml);
1211
+ } catch (error) {
1212
+ console.error(error);
1213
+ res.send('Something needs to be fixed!');
1214
+ }
1215
+ });
1216
+
1217
+ app.get('/talk', async (req, res, next) => {
1218
+ try {
1219
+ res.send(chatHtml);
1220
+ } catch (error) {
1221
+ console.error(error);
1222
+ res.send('Something needs to be fixed!');
1223
+ }
1224
+ });
1225
+
1226
+ app.post(
1227
+ '/openai',
1228
+ async (req, res, next) => {
1229
+ const functions = [
1230
+ {
1231
+ "type": "function",
1232
+ "function": {
1233
+ "name": "getCompanyCreds",
1234
+ "description": "Retrieves credentials for a specific company based on its ID.",
1235
+ "parameters": {
1236
+ "type": "object",
1237
+ "properties": {
1238
+ "company_id": {
1239
+ "type": "number",
1240
+ "description": "Unique identifier of the company."
1241
+ }
1242
+ },
1243
+ "required": ["company_id"]
1244
+ }
1245
+ }
1246
+ },
1247
+ {
1248
+ "type": "function",
1249
+ "function": {
1250
+ "name": "createUpdateCompanyCreds",
1251
+ "description": "Creates or updates credentials for a company.",
1252
+ "parameters": {
1253
+ "type": "object",
1254
+ "properties": {
1255
+ "company_id": {
1256
+ "type": "number",
1257
+ "description": "Unique identifier of the company."
1258
+ },
1259
+ "clientId": {
1260
+ "type": "string",
1261
+ "description": "Client ID for authentication."
1262
+ },
1263
+ "clientSecret": {
1264
+ "type": "string",
1265
+ "description": "Client secret for authentication."
1266
+ }
1267
+ },
1268
+ "required": ["company_id", "clientId", "clientSecret"]
1269
+ }
1270
+ }
1271
+ },
1272
+ {
1273
+ "type": "function",
1274
+ "function": {
1275
+ "name": "getApplications",
1276
+ "description": "Retrieves a list of applications associated with a specific company ID.",
1277
+ "parameters": {
1278
+ "type": "object",
1279
+ "properties": {
1280
+ "company_id": {
1281
+ "type": "number",
1282
+ "description": "Unique identifier of the company."
1283
+ }
1284
+ },
1285
+ "required": ["company_id"]
1286
+ }
1287
+ }
1288
+ },
1289
+ {
1290
+ "type": "function",
1291
+ "function": {
1292
+ "name": "createBrand",
1293
+ "description": "Creates a new brand under a specific company.",
1294
+ "parameters": {
1295
+ "type": "object",
1296
+ "properties": {
1297
+ "company_id": {
1298
+ "type": "number",
1299
+ "description": "Unique identifier of the company."
1300
+ },
1301
+ "name": {
1302
+ "type": "string",
1303
+ "description": "Name of the new brand."
1304
+ },
1305
+ "description": {
1306
+ "type": "string",
1307
+ "description": "Description of the new brand."
1308
+ },
1309
+ "logo": {
1310
+ "type": "string",
1311
+ "description": "URL of the brand's logo."
1312
+ }
1313
+ },
1314
+ "required": ["company_id", "name", "description"]
1315
+ }
1316
+ }
1317
+ },
1318
+ {
1319
+ "type": "function",
1320
+ "function": {
1321
+ "name": "updateBrand",
1322
+ "description": "Updates the details of an existing brand within a company.",
1323
+ "parameters": {
1324
+ "type": "object",
1325
+ "properties": {
1326
+ "company_id": {
1327
+ "type": "number",
1328
+ "description": "Unique identifier of the company."
1329
+ },
1330
+ "brand_id": {
1331
+ "type": "string",
1332
+ "description": "Unique identifier of the brand to be updated."
1333
+ },
1334
+ "name": {
1335
+ "type": "string",
1336
+ "description": "New name for the brand."
1337
+ },
1338
+ "description": {
1339
+ "type": "string",
1340
+ "description": "New description for the brand."
1341
+ },
1342
+ "logo": {
1343
+ "type": "string",
1344
+ "description": "New URL for the brand's logo."
1345
+ },
1346
+ },
1347
+ "required": ["company_id", "brand_id", "name", "description"]
1348
+ }
1349
+ }
1350
+ },
1351
+ {
1352
+ "type": "function",
1353
+ "function": {
1354
+ "name": "getBrands",
1355
+ "description": "Retrieves a list of all brands associated with a specific company.",
1356
+ "parameters": {
1357
+ "type": "object",
1358
+ "properties": {
1359
+ "company_id": {
1360
+ "type": "number",
1361
+ "description": "Unique identifier of the company for which brands are being retrieved."
1362
+ }
1363
+ },
1364
+ "required": ["company_id"]
1365
+ }
1366
+ }
1367
+ },
1368
+ {
1369
+ "type": "function",
1370
+ "function": {
1371
+ "name": "getLocations",
1372
+ "description": "Retrieves a list of all locations associated with a specific company.",
1373
+ "parameters": {
1374
+ "type": "object",
1375
+ "properties": {
1376
+ "company_id": {
1377
+ "type": "number",
1378
+ "description": "Unique identifier of the company for which locations are being retrieved."
1379
+ }
1380
+ },
1381
+ "required": ["company_id"]
1382
+ }
1383
+ }
1384
+ },
1385
+ {
1386
+ "type": "function",
1387
+ "function": {
1388
+ "name": "createLocation",
1389
+ "description": "Creates a new location for a specified company.",
1390
+ "parameters": {
1391
+ "type": "object",
1392
+ "properties": {
1393
+ "company_id": {
1394
+ "type": "number",
1395
+ "description": "Unique identifier of the company."
1396
+ },
1397
+ "address1": {
1398
+ "type": "string",
1399
+ "description": "Primary address line of the new location."
1400
+ },
1401
+ "address2": {
1402
+ "type": "string",
1403
+ "description": "Secondary address line of the new location."
1404
+ },
1405
+ "pincode": {
1406
+ "type": "string",
1407
+ "description": "Postal code of the new location."
1408
+ },
1409
+ "state": {
1410
+ "type": "string",
1411
+ "description": "State where the new location is situated."
1412
+ },
1413
+ "city": {
1414
+ "type": "string",
1415
+ "description": "City where the new location is situated."
1416
+ },
1417
+ "number": {
1418
+ "type": "string",
1419
+ "description": "Contact number for the new location."
1420
+ },
1421
+ "country_code": {
1422
+ "type": "string",
1423
+ "description": "Country code for the contact number."
1424
+ },
1425
+ "gst_name": {
1426
+ "type": "string",
1427
+ "description": "GST registered name associated with the new location."
1428
+ },
1429
+ "gst_no": {
1430
+ "type": "string",
1431
+ "description": "GST number associated with the new location."
1432
+ },
1433
+ "latitude": {
1434
+ "type": "number",
1435
+ "description": "Latitude coordinate for the new location."
1436
+ },
1437
+ "longitude": {
1438
+ "type": "number",
1439
+ "description": "Longitude coordinate for the new location."
1440
+ }
1441
+ },
1442
+ "required": ["company_id", "address1", "city", "state", "pincode", "country_code", "gst_name", "gst_no"]
1443
+ }
1444
+ }
1445
+ },
1446
+ {
1447
+ "type": "function",
1448
+ "function": {
1449
+ "name": "updateLocation",
1450
+ "description": "update a existing location for a specified company.",
1451
+ "parameters": {
1452
+ "type": "object",
1453
+ "properties": {
1454
+ "company_id": {
1455
+ "type": "number",
1456
+ "description": "Unique identifier of the company."
1457
+ },
1458
+ "location_id": {
1459
+ "type": "number",
1460
+ "description": "Unique identifier of the location."
1461
+ },
1462
+ "address1": {
1463
+ "type": "string",
1464
+ "description": "Primary address line of the new location."
1465
+ },
1466
+ "address2": {
1467
+ "type": "string",
1468
+ "description": "Secondary address line of the new location."
1469
+ },
1470
+ "pincode": {
1471
+ "type": "string",
1472
+ "description": "Postal code of the new location."
1473
+ },
1474
+ "state": {
1475
+ "type": "string",
1476
+ "description": "State where the new location is situated."
1477
+ },
1478
+ "city": {
1479
+ "type": "string",
1480
+ "description": "City where the new location is situated."
1481
+ },
1482
+ "number": {
1483
+ "type": "string",
1484
+ "description": "Contact number for the new location."
1485
+ },
1486
+ "country_code": {
1487
+ "type": "string",
1488
+ "description": "Country code for the contact number."
1489
+ },
1490
+ "gst_name": {
1491
+ "type": "string",
1492
+ "description": "GST registered name associated with the new location."
1493
+ },
1494
+ "gst_no": {
1495
+ "type": "string",
1496
+ "description": "GST number associated with the new location."
1497
+ },
1498
+ "latitude": {
1499
+ "type": "number",
1500
+ "description": "Latitude coordinate for the new location."
1501
+ },
1502
+ "longitude": {
1503
+ "type": "number",
1504
+ "description": "Longitude coordinate for the new location."
1505
+ }
1506
+ },
1507
+ "required": ["company_id", 'brand_id', "address1", "city", "state", "pincode", "country_code", "gst_name", "gst_no"]
1508
+ }
1509
+ }
1510
+ },
1511
+ {
1512
+ "type": "function",
1513
+ "function": {
1514
+ "name": "createProduct",
1515
+ "description": "Creates a new product in the company's catalog.",
1516
+ "parameters": {
1517
+ "type": "object",
1518
+ "properties": {
1519
+ "name": {
1520
+ "type": "string",
1521
+ "description": "Name of the new product."
1522
+ },
1523
+ "company_id": {
1524
+ "type": "number",
1525
+ "description": "Unique identifier of the company."
1526
+ },
1527
+ "slug": {
1528
+ "type": "string",
1529
+ "description": "SEO-friendly URL segment for the product."
1530
+ },
1531
+ "seller_identifier": {
1532
+ "type": "string",
1533
+ "description": "Unique identifier for the seller of the product."
1534
+ },
1535
+ "brand_id": {
1536
+ "type": "number",
1537
+ "description": "Unique identifier of the brand associated with the product."
1538
+ },
1539
+ "mrp": {
1540
+ "type": "number",
1541
+ "description": "Maximum Retail Price of the product."
1542
+ },
1543
+ "selling_price": {
1544
+ "type": "number",
1545
+ "description": "Selling price of the product."
1546
+ }
1547
+ },
1548
+ "required": ["name", "company_id", "slug", "seller_identifier", "brand_id"]
1549
+ }
1550
+ }
1551
+ },
1552
+ {
1553
+ "type": "function",
1554
+ "function": {
1555
+ "name": "createInventory",
1556
+ "description": "Creates a new inventory record for a specific product in a company.",
1557
+ "parameters": {
1558
+ "type": "object",
1559
+ "properties": {
1560
+ "company_id": {
1561
+ "type": "number",
1562
+ "description": "Unique identifier of the company."
1563
+ },
1564
+ "product_id": {
1565
+ "type": "number",
1566
+ "description": "Unique identifier of the product."
1567
+ },
1568
+ "seller_identifier": {
1569
+ "type": "string",
1570
+ "description": "Unique identifier for the seller of the product."
1571
+ },
1572
+ "location_id": {
1573
+ "type": "number",
1574
+ "description": "Unique identifier of the location where the inventory is stored."
1575
+ },
1576
+ "mrp": {
1577
+ "type": "number",
1578
+ "description": "Maximum Retail Price of the product."
1579
+ },
1580
+ "selling_price": {
1581
+ "type": "number",
1582
+ "description": "Selling price of the product."
1583
+ }
1584
+ },
1585
+ "required": ["company_id", "product_id", "seller_identifier", "location_id"]
1586
+ }
1587
+ }
1588
+ },
1589
+ {
1590
+ "type": "function",
1591
+ "function": {
1592
+ "name": "createApplication",
1593
+ "description": "Creates a new application for a specified company.",
1594
+ "parameters": {
1595
+ "type": "object",
1596
+ "properties": {
1597
+ "company_id": {
1598
+ "type": "number",
1599
+ "description": "Unique identifier of the company."
1600
+ },
1601
+ "brand_ids": {
1602
+ "type": "array",
1603
+ "description": "Array of brand IDs associated with the application.",
1604
+ "items": {
1605
+ "type": "number"
1606
+ }
1607
+ },
1608
+ "name": {
1609
+ "type": "string",
1610
+ "description": "Name of the new application."
1611
+ },
1612
+ "subdomain": {
1613
+ "type": "string",
1614
+ "description": "Subdomain for the application's URL."
1615
+ }
1616
+ },
1617
+ "required": ["company_id", "brand_ids", "name", "subdomain"]
1618
+ }
1619
+ }
1620
+ }
1621
+ ];
1622
+
1623
+ const messages = [{
1624
+ role: 'system',
1625
+ content: 'You are Jio Copilot. Introducing an all-encompassing tool, designed to seamlessly interact with TiraBeauty, JioCinema, JioMart, and JioFiber, catering to multiple facets of your digital lifestyle.\nOur JioMart integration simplifies your online shopping journey, providing a wide selection of products, from clothing and electronics to grocery items, all in one convenient location. JioMart can help to buy ingredients from recipes. Search each ingredient separately.\nWith TiraBeauty functionality, you can explore a wide array of health and beauty products, effortlessly manage your shopping cart, and share your cart selections via a QR code within the ecosystem of www.tirabeauty.com - your comprehensive ecommerce destination for beauty products and accessories.\nThe JioCinema feature takes you on an immersive streaming adventure, offering access to a diverse range of television shows, movies, sports content, and much more. Easily search and stream content to match your mood, directly from this interface.\nFinally, the JioFiber functionality empowers you to navigate through a range of lightning-fast internet and data plans from this leading broadband service provider. Explore and choose from a comprehensive list of prepaid and postpaid plans to meet your connectivity needs.\nEquip yourself with this multifunctional tool and experience a streamlined, efficient digital experience across a variety of platforms.'
1626
+ }];
1627
+ const session = req.jio_copilot_anonymous_session;
1628
+ if (session) {
1629
+ messages.push(...(await listCache.getAll(session)));
1630
+ }
1631
+
1632
+ const userMessage = { role: 'user', content: req.body.prompt };
1633
+ messages.push(userMessage);
1634
+ await listCache.setItems(session, userMessage);
1635
+
1636
+ res.setHeader('Cache-Control', 'no-cache');
1637
+ res.setHeader('Content-Type', 'text/event-stream');
1638
+ // res.setHeader('Access-Control-Allow-Origin', http://);
1639
+ res.setHeader('Connection', 'keep-alive');
1640
+ res.flushHeaders();
1641
+
1642
+ try {
1643
+ // await nextStep(session, messages, skills, functions, res);
1644
+ res.end();
1645
+ } catch (error) {
1646
+ if (error.code === 'context_length_exceeded') {
1647
+ res.write('You have exhausted the conversation limit, clear history and start again!');
1648
+ res.end();
1649
+ }
1650
+ res.write('There is some issue is going on. Please try again later.');
1651
+ res.end();
1652
+ }
1653
+ });
1654
+
1655
+
1656
  app.use(errorHandler)
1657
 
1658
  app.listen(port, async () => {
 
1664
  await fs.writeFileSync("swagger.yaml", swaggerYAML, 'utf-8')
1665
  await fs.writeFileSync("swagger.json", JSON.stringify(swaggerSpec, null, 2), 'utf-8')
1666
  });
1667
+
1668
+ // async function nextStep(session, messages, skills, functions, res) {
1669
+ // const conn = new OpenAI({ apiKey: "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" });
1670
+ // const streamResponse = await conn
1671
+ // .chat.completions.create({
1672
+ // model: 'gpt-4-1106-preview',
1673
+ // messages,
1674
+ // functions,
1675
+ // function_call: 'auto',
1676
+ // temperature: 0.5,
1677
+ // stream: true
1678
+ // }).catch(async err => {
1679
+ // console.error(err);
1680
+ // const openAIError = new Error(err.error.message);
1681
+ // openAIError.code = err.error.code;
1682
+ // throw openAIError;
1683
+ // });
1684
+
1685
+ // let finalMessage = '';
1686
+ // const functionCall = { name: null, arguments: '' };
1687
+
1688
+ // for await (const line of streamResponse) {
1689
+ // const choice = line.choices[0];
1690
+ // if (choice.delta.function_call) {
1691
+ // const fc = choice.delta.function_call;
1692
+ // if (fc.name) {
1693
+ // // res.write(`Detected Function: ${fc.name}\n\n`);
1694
+ // // res.flush();
1695
+ // functionCall.name = fc.name;
1696
+ // }
1697
+ // if (fc.arguments) {
1698
+ // functionCall.arguments += fc.arguments;
1699
+ // }
1700
+ // } else if (!choice.finish_reason && choice.delta.content) {
1701
+ // finalMessage += choice.delta.content;
1702
+ // res.write(`${choice.delta.content}`);
1703
+ // res.flush();
1704
+ // }
1705
+ // }
1706
+
1707
+ // if (!functionCall.name) {
1708
+ // const assistantMessage = { role: 'assistant', content: finalMessage };
1709
+ // messages.push(assistantMessage);
1710
+ // await listCache.setItems(session, assistantMessage);
1711
+ // return;
1712
+ // }
1713
+
1714
+ // const functionName = functionCall.name;
1715
+ // const args = JSON.parse(functionCall.arguments);
1716
+ // if (!skills[functionName]) {
1717
+ // throw new Error(`No skill implemented for this function: ${functionName}`);
1718
+ // }
1719
+
1720
+ // // res.write(`Executing Function: ${functionName} with arguments ${JSON.stringify(args)} \n\n`);
1721
+ // // res.flush();
1722
+ // const skill = new skills[functionName]({ ...args, headers: { 'openai-ephemeral-user-id': session } });
1723
+ // const skillRes = await skill.performAction();
1724
+ // if (skillRes) {
1725
+ // const functionMessage = { role: 'function', name: functionName, content: JSON.stringify(skillRes) };
1726
+ // messages.push(functionMessage);
1727
+ // await listCache.setItems(session, functionMessage);
1728
+ // }
1729
+ // return nextStep(conn, session, messages, skills, functions, res);
1730
+ // }
package.json CHANGED
@@ -15,6 +15,7 @@
15
  "express": "^4.18.2",
16
  "ioredis": "^5.3.2",
17
  "js-yaml": "^4.1.0",
 
18
  "swagger-jsdoc": "^6.2.8"
19
  }
20
  }
 
15
  "express": "^4.18.2",
16
  "ioredis": "^5.3.2",
17
  "js-yaml": "^4.1.0",
18
+ "openai": "^4.20.1",
19
  "swagger-jsdoc": "^6.2.8"
20
  }
21
  }
swagger.json CHANGED
@@ -302,7 +302,7 @@
302
  "name": "brandId",
303
  "required": true,
304
  "schema": {
305
- "type": "string"
306
  },
307
  "description": "The unique identifier of the brand"
308
  }
@@ -551,14 +551,14 @@
551
  }
552
  }
553
  },
554
- "/company/{companyId}/departments": {
555
- "get": {
556
- "summary": "Retrieve departments for a specific company",
557
- "description": "Fetches a list of departments associated with the given company ID.",
 
558
  "tags": [
559
- "Company"
560
  ],
561
- "operationId": "getCompanyDepartments",
562
  "parameters": [
563
  {
564
  "in": "path",
@@ -567,27 +567,73 @@
567
  "schema": {
568
  "type": "string"
569
  },
570
- "description": "The unique identifier of the company"
571
  }
572
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
  "responses": {
574
  "200": {
575
- "description": "An array of department objects",
576
  "content": {
577
  "application/json": {
578
  "schema": {
579
- "type": "array",
580
- "items": {
581
- "type": "object",
582
- "properties": {
583
- "name": {
584
- "type": "string",
585
- "description": "Name of the department"
586
- },
587
- "slug": {
588
- "type": "string",
589
- "description": "slug or identifier of the department"
590
- }
591
  }
592
  }
593
  }
@@ -596,6 +642,162 @@
596
  }
597
  }
598
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599
  }
600
  },
601
  "components": {
 
302
  "name": "brandId",
303
  "required": true,
304
  "schema": {
305
+ "type": "number"
306
  },
307
  "description": "The unique identifier of the brand"
308
  }
 
551
  }
552
  }
553
  },
554
+ "/company/{companyId}/products": {
555
+ "post": {
556
+ "summary": "Creates a new product for a given company.",
557
+ "description": "This endpoint creates a new product with various attributes including name, slug, pricing, and more.",
558
+ "operationId": "createProduct",
559
  "tags": [
560
+ "Products"
561
  ],
 
562
  "parameters": [
563
  {
564
  "in": "path",
 
567
  "schema": {
568
  "type": "string"
569
  },
570
+ "description": "Unique identifier of the company."
571
  }
572
  ],
573
+ "requestBody": {
574
+ "required": true,
575
+ "content": {
576
+ "application/json": {
577
+ "schema": {
578
+ "type": "object",
579
+ "required": [
580
+ "name",
581
+ "slug",
582
+ "seller_identifier",
583
+ "brand_id"
584
+ ],
585
+ "properties": {
586
+ "name": {
587
+ "type": "string",
588
+ "description": "Name of the product."
589
+ },
590
+ "slug": {
591
+ "type": "string",
592
+ "description": "URL-friendly identifier for the product."
593
+ },
594
+ "seller_identifier": {
595
+ "type": "string",
596
+ "description": "Unique identifier for the seller."
597
+ },
598
+ "brand_id": {
599
+ "type": "string",
600
+ "description": "Unique identifier for the brand."
601
+ },
602
+ "location_id": {
603
+ "type": "string",
604
+ "description": "Location identifier for the product."
605
+ },
606
+ "mrp": {
607
+ "type": "number",
608
+ "default": 999,
609
+ "description": "Maximum retail price of the product."
610
+ },
611
+ "selling_price": {
612
+ "type": "number",
613
+ "default": 499,
614
+ "description": "Selling price of the product."
615
+ }
616
+ }
617
+ }
618
+ }
619
+ }
620
+ },
621
  "responses": {
622
  "200": {
623
+ "description": "Successful creation of the product.",
624
  "content": {
625
  "application/json": {
626
  "schema": {
627
+ "type": "object",
628
+ "properties": {
629
+ "message": {
630
+ "type": "string"
631
+ },
632
+ "id": {
633
+ "type": "string"
634
+ },
635
+ "seller_identifier": {
636
+ "type": "string"
 
 
637
  }
638
  }
639
  }
 
642
  }
643
  }
644
  }
645
+ },
646
+ "/company/{companyId}/products/{productId}/inventory": {
647
+ "post": {
648
+ "summary": "Updates inventory for a specific product.",
649
+ "description": "This endpoint updates the inventory details for a given product, including location, pricing, and quantity.",
650
+ "operationId": "updateInventory",
651
+ "tags": [
652
+ "Inventory"
653
+ ],
654
+ "parameters": [
655
+ {
656
+ "in": "path",
657
+ "name": "companyId",
658
+ "required": true,
659
+ "schema": {
660
+ "type": "string"
661
+ },
662
+ "description": "Unique identifier of the company."
663
+ },
664
+ {
665
+ "in": "path",
666
+ "name": "productId",
667
+ "required": true,
668
+ "schema": {
669
+ "type": "string"
670
+ },
671
+ "description": "Unique identifier of the product."
672
+ }
673
+ ],
674
+ "requestBody": {
675
+ "required": true,
676
+ "content": {
677
+ "application/json": {
678
+ "schema": {
679
+ "type": "object",
680
+ "required": [
681
+ "location_id",
682
+ "seller_identifier"
683
+ ],
684
+ "properties": {
685
+ "location_id": {
686
+ "type": "string",
687
+ "description": "Location identifier where the inventory is stored."
688
+ },
689
+ "mrp": {
690
+ "type": "number",
691
+ "default": 999,
692
+ "description": "Maximum retail price of the product."
693
+ },
694
+ "selling_price": {
695
+ "type": "number",
696
+ "default": 499,
697
+ "description": "Selling price of the product."
698
+ },
699
+ "seller_identifier": {
700
+ "type": "string",
701
+ "description": "Unique identifier for the seller."
702
+ }
703
+ }
704
+ }
705
+ }
706
+ }
707
+ },
708
+ "responses": {
709
+ "200": {
710
+ "description": "Successful update of inventory.",
711
+ "content": {
712
+ "application/json": {
713
+ "schema": {
714
+ "type": "object",
715
+ "properties": {
716
+ "message": {
717
+ "type": "string"
718
+ }
719
+ }
720
+ }
721
+ }
722
+ }
723
+ }
724
+ }
725
+ }
726
+ },
727
+ "/company/{companyId}/sales_channel": {
728
+ "post": {
729
+ "operationId": "addSalesChannel",
730
+ "summary": "Create a sales channel for a given company",
731
+ "description": "This endpoint creates a new sales channel for the specified company.",
732
+ "tags": [
733
+ "Sales Channel"
734
+ ],
735
+ "parameters": [
736
+ {
737
+ "in": "path",
738
+ "name": "companyId",
739
+ "required": true,
740
+ "schema": {
741
+ "type": "string"
742
+ },
743
+ "description": "The ID of the company"
744
+ }
745
+ ],
746
+ "requestBody": {
747
+ "required": true,
748
+ "content": {
749
+ "application/json": {
750
+ "schema": {
751
+ "type": "object",
752
+ "properties": {
753
+ "brand_ids": {
754
+ "type": "array",
755
+ "items": {
756
+ "type": "integer"
757
+ },
758
+ "description": "Array of brand IDs to be associated with the sales channel"
759
+ },
760
+ "name": {
761
+ "type": "string",
762
+ "description": "Name of the sales channel"
763
+ },
764
+ "subdomain": {
765
+ "type": "string",
766
+ "description": "subdomain associated with the sales channel"
767
+ }
768
+ }
769
+ }
770
+ }
771
+ }
772
+ },
773
+ "responses": {
774
+ "200": {
775
+ "description": "Sales channel successfully created",
776
+ "content": {
777
+ "application/json": {
778
+ "schema": {
779
+ "type": "object",
780
+ "properties": {
781
+ "message": {
782
+ "type": "string"
783
+ },
784
+ "app": {
785
+ "type": "object",
786
+ "description": "Details of the created sales channel"
787
+ }
788
+ }
789
+ }
790
+ }
791
+ }
792
+ },
793
+ "400": {
794
+ "description": "Bad request"
795
+ },
796
+ "500": {
797
+ "description": "Internal server error"
798
+ }
799
+ }
800
+ }
801
  }
802
  },
803
  "components": {
swagger.yaml CHANGED
@@ -194,7 +194,7 @@ paths:
194
  name: brandId
195
  required: true
196
  schema:
197
- type: string
198
  description: The unique identifier of the brand
199
  requestBody:
200
  required: true
@@ -350,36 +350,176 @@ paths:
350
  application/json:
351
  schema:
352
  $ref: '#/components/schemas/ErrorResponse'
353
- /company/{companyId}/departments:
354
- get:
355
- summary: Retrieve departments for a specific company
356
- description: Fetches a list of departments associated with the given company ID.
 
 
 
357
  tags:
358
- - Company
359
- operationId: getCompanyDepartments
360
  parameters:
361
  - in: path
362
  name: companyId
363
  required: true
364
  schema:
365
  type: string
366
- description: The unique identifier of the company
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  responses:
368
  '200':
369
- description: An array of department objects
370
  content:
371
  application/json:
372
  schema:
373
- type: array
374
- items:
375
- type: object
376
- properties:
377
- name:
378
- type: string
379
- description: Name of the department
380
- slug:
381
- type: string
382
- description: slug or identifier of the department
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  components:
384
  schemas:
385
  CompanyCreds:
 
194
  name: brandId
195
  required: true
196
  schema:
197
+ type: number
198
  description: The unique identifier of the brand
199
  requestBody:
200
  required: true
 
350
  application/json:
351
  schema:
352
  $ref: '#/components/schemas/ErrorResponse'
353
+ /company/{companyId}/products:
354
+ post:
355
+ summary: Creates a new product for a given company.
356
+ description: >-
357
+ This endpoint creates a new product with various attributes including
358
+ name, slug, pricing, and more.
359
+ operationId: createProduct
360
  tags:
361
+ - Products
 
362
  parameters:
363
  - in: path
364
  name: companyId
365
  required: true
366
  schema:
367
  type: string
368
+ description: Unique identifier of the company.
369
+ requestBody:
370
+ required: true
371
+ content:
372
+ application/json:
373
+ schema:
374
+ type: object
375
+ required:
376
+ - name
377
+ - slug
378
+ - seller_identifier
379
+ - brand_id
380
+ properties:
381
+ name:
382
+ type: string
383
+ description: Name of the product.
384
+ slug:
385
+ type: string
386
+ description: URL-friendly identifier for the product.
387
+ seller_identifier:
388
+ type: string
389
+ description: Unique identifier for the seller.
390
+ brand_id:
391
+ type: string
392
+ description: Unique identifier for the brand.
393
+ location_id:
394
+ type: string
395
+ description: Location identifier for the product.
396
+ mrp:
397
+ type: number
398
+ default: 999
399
+ description: Maximum retail price of the product.
400
+ selling_price:
401
+ type: number
402
+ default: 499
403
+ description: Selling price of the product.
404
  responses:
405
  '200':
406
+ description: Successful creation of the product.
407
  content:
408
  application/json:
409
  schema:
410
+ type: object
411
+ properties:
412
+ message:
413
+ type: string
414
+ id:
415
+ type: string
416
+ seller_identifier:
417
+ type: string
418
+ /company/{companyId}/products/{productId}/inventory:
419
+ post:
420
+ summary: Updates inventory for a specific product.
421
+ description: >-
422
+ This endpoint updates the inventory details for a given product,
423
+ including location, pricing, and quantity.
424
+ operationId: updateInventory
425
+ tags:
426
+ - Inventory
427
+ parameters:
428
+ - in: path
429
+ name: companyId
430
+ required: true
431
+ schema:
432
+ type: string
433
+ description: Unique identifier of the company.
434
+ - in: path
435
+ name: productId
436
+ required: true
437
+ schema:
438
+ type: string
439
+ description: Unique identifier of the product.
440
+ requestBody:
441
+ required: true
442
+ content:
443
+ application/json:
444
+ schema:
445
+ type: object
446
+ required:
447
+ - location_id
448
+ - seller_identifier
449
+ properties:
450
+ location_id:
451
+ type: string
452
+ description: Location identifier where the inventory is stored.
453
+ mrp:
454
+ type: number
455
+ default: 999
456
+ description: Maximum retail price of the product.
457
+ selling_price:
458
+ type: number
459
+ default: 499
460
+ description: Selling price of the product.
461
+ seller_identifier:
462
+ type: string
463
+ description: Unique identifier for the seller.
464
+ responses:
465
+ '200':
466
+ description: Successful update of inventory.
467
+ content:
468
+ application/json:
469
+ schema:
470
+ type: object
471
+ properties:
472
+ message:
473
+ type: string
474
+ /company/{companyId}/sales_channel:
475
+ post:
476
+ operationId: addSalesChannel
477
+ summary: Create a sales channel for a given company
478
+ description: This endpoint creates a new sales channel for the specified company.
479
+ tags:
480
+ - Sales Channel
481
+ parameters:
482
+ - in: path
483
+ name: companyId
484
+ required: true
485
+ schema:
486
+ type: string
487
+ description: The ID of the company
488
+ requestBody:
489
+ required: true
490
+ content:
491
+ application/json:
492
+ schema:
493
+ type: object
494
+ properties:
495
+ brand_ids:
496
+ type: array
497
+ items:
498
+ type: integer
499
+ description: Array of brand IDs to be associated with the sales channel
500
+ name:
501
+ type: string
502
+ description: Name of the sales channel
503
+ subdomain:
504
+ type: string
505
+ description: subdomain associated with the sales channel
506
+ responses:
507
+ '200':
508
+ description: Sales channel successfully created
509
+ content:
510
+ application/json:
511
+ schema:
512
+ type: object
513
+ properties:
514
+ message:
515
+ type: string
516
+ app:
517
+ type: object
518
+ description: Details of the created sales channel
519
+ '400':
520
+ description: Bad request
521
+ '500':
522
+ description: Internal server error
523
  components:
524
  schemas:
525
  CompanyCreds:
utils.js CHANGED
@@ -14,7 +14,7 @@ export const initClient = async (companyId) => {
14
  apiKey: creds.clientId,
15
  apiSecret: creds.clientSecret,
16
  useAutoRenewTimer: true,
17
- // domain: "https://api.fyndx5.de"
18
  }
19
  const platformConfig = new PlatformConfig(config)
20
  let token = await redis.get(`${companyId}:client_token`)
 
14
  apiKey: creds.clientId,
15
  apiSecret: creds.clientSecret,
16
  useAutoRenewTimer: true,
17
+ domain: "https://api.fyndx5.de"
18
  }
19
  const platformConfig = new PlatformConfig(config)
20
  let token = await redis.get(`${companyId}:client_token`)
vercel.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": 2,
3
+ "builds": [
4
+ {
5
+ "src": "index.js",
6
+ "use": "@now/node"
7
+ }
8
+ ],
9
+ "routes": [
10
+ {
11
+ "src": "/(.*)",
12
+ "dest": "index.js"
13
+ }
14
+ ]
15
+ }
yarn.lock CHANGED
@@ -174,11 +174,40 @@
174
  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
175
  integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  "@ungap/structured-clone@^1.2.0":
178
  version "1.2.0"
179
  resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
180
  integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
181
 
 
 
 
 
 
 
 
182
  accepts@~1.3.8:
183
  version "1.3.8"
184
  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
@@ -197,6 +226,13 @@ acorn@^8.9.0:
197
  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b"
198
  integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==
199
 
 
 
 
 
 
 
 
200
  ajv@^6.12.4:
201
  version "6.12.6"
202
  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@@ -247,6 +283,11 @@ balanced-match@^1.0.0:
247
  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
248
  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
249
 
 
 
 
 
 
250
  body-parser@1.20.1:
251
  version "1.20.1"
252
  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
@@ -310,6 +351,11 @@ chalk@^4.0.0:
310
  ansi-styles "^4.1.0"
311
  supports-color "^7.1.0"
312
 
 
 
 
 
 
313
  cluster-key-slot@^1.1.0:
314
  version "1.1.2"
315
  resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
@@ -388,6 +434,11 @@ cross-spawn@^7.0.2:
388
  shebang-command "^2.0.0"
389
  which "^2.0.1"
390
 
 
 
 
 
 
391
  crypto-js@^4.1.1:
392
  version "4.2.0"
393
  resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
@@ -446,6 +497,14 @@ destroy@1.2.0:
446
  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
447
  integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
448
 
 
 
 
 
 
 
 
 
449
  doctrine@3.0.0, doctrine@^3.0.0:
450
  version "3.0.0"
451
  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
@@ -568,6 +627,11 @@ etag@~1.8.1:
568
  resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
569
  integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
570
 
 
 
 
 
 
571
  express@^4.18.2:
572
  version "4.18.2"
573
  resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
@@ -679,6 +743,11 @@ follow-redirects@^1.14.9:
679
  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
680
  integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
681
 
 
 
 
 
 
682
  form-data@^4.0.0:
683
  version "4.0.0"
684
  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
@@ -688,6 +757,14 @@ form-data@^4.0.0:
688
  combined-stream "^1.0.8"
689
  mime-types "^2.1.12"
690
 
 
 
 
 
 
 
 
 
691
  forwarded@0.2.0:
692
  version "0.2.0"
693
  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -808,6 +885,13 @@ http-errors@2.0.0:
808
  statuses "2.0.1"
809
  toidentifier "1.0.1"
810
 
 
 
 
 
 
 
 
811
  iconv-lite@0.4.24:
812
  version "0.4.24"
813
  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -866,6 +950,11 @@ ipaddr.js@1.9.1:
866
  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
867
  integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
868
 
 
 
 
 
 
869
  is-extglob@^2.1.1:
870
  version "2.1.1"
871
  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
@@ -983,6 +1072,15 @@ loglevel@^1.8.1:
983
  resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4"
984
  integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==
985
 
 
 
 
 
 
 
 
 
 
986
  media-typer@0.3.0:
987
  version "0.3.0"
988
  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@@ -1032,7 +1130,7 @@ ms@2.1.2:
1032
  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
1033
  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
1034
 
1035
- ms@2.1.3:
1036
  version "2.1.3"
1037
  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
1038
  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -1047,6 +1145,18 @@ negotiator@0.6.3:
1047
  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
1048
  integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
1049
 
 
 
 
 
 
 
 
 
 
 
 
 
1050
  object-inspect@^1.9.0:
1051
  version "1.13.1"
1052
  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
@@ -1066,6 +1176,21 @@ once@^1.3.0:
1066
  dependencies:
1067
  wrappy "1"
1068
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1069
  optionator@^0.9.3:
1070
  version "0.9.3"
1071
  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
@@ -1358,6 +1483,11 @@ toidentifier@1.0.1:
1358
  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
1359
  integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
1360
 
 
 
 
 
 
1361
  type-check@^0.4.0, type-check@~0.4.0:
1362
  version "0.4.0"
1363
  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -1378,6 +1508,11 @@ type-is@~1.6.18:
1378
  media-typer "0.3.0"
1379
  mime-types "~2.1.24"
1380
 
 
 
 
 
 
1381
  unpipe@1.0.0, unpipe@~1.0.0:
1382
  version "1.0.0"
1383
  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -1405,6 +1540,29 @@ vary@~1.1.2:
1405
  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
1406
  integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
1407
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1408
  which@^2.0.1:
1409
  version "2.0.2"
1410
  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
 
174
  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
175
  integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
176
 
177
+ "@types/node-fetch@^2.6.4":
178
+ version "2.6.9"
179
+ resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.9.tgz#15f529d247f1ede1824f7e7acdaa192d5f28071e"
180
+ integrity sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==
181
+ dependencies:
182
+ "@types/node" "*"
183
+ form-data "^4.0.0"
184
+
185
+ "@types/node@*":
186
+ version "20.10.4"
187
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.4.tgz#b246fd84d55d5b1b71bf51f964bd514409347198"
188
+ integrity sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==
189
+ dependencies:
190
+ undici-types "~5.26.4"
191
+
192
+ "@types/node@^18.11.18":
193
+ version "18.19.3"
194
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.3.tgz#e4723c4cb385641d61b983f6fe0b716abd5f8fc0"
195
+ integrity sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==
196
+ dependencies:
197
+ undici-types "~5.26.4"
198
+
199
  "@ungap/structured-clone@^1.2.0":
200
  version "1.2.0"
201
  resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
202
  integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
203
 
204
+ abort-controller@^3.0.0:
205
+ version "3.0.0"
206
+ resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
207
+ integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
208
+ dependencies:
209
+ event-target-shim "^5.0.0"
210
+
211
  accepts@~1.3.8:
212
  version "1.3.8"
213
  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
 
226
  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b"
227
  integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==
228
 
229
+ agentkeepalive@^4.2.1:
230
+ version "4.5.0"
231
+ resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923"
232
+ integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
233
+ dependencies:
234
+ humanize-ms "^1.2.1"
235
+
236
  ajv@^6.12.4:
237
  version "6.12.6"
238
  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
 
283
  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
284
  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
285
 
286
+ base-64@^0.1.0:
287
+ version "0.1.0"
288
+ resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb"
289
+ integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==
290
+
291
  body-parser@1.20.1:
292
  version "1.20.1"
293
  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
 
351
  ansi-styles "^4.1.0"
352
  supports-color "^7.1.0"
353
 
354
+ charenc@0.0.2:
355
+ version "0.0.2"
356
+ resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
357
+ integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==
358
+
359
  cluster-key-slot@^1.1.0:
360
  version "1.1.2"
361
  resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
 
434
  shebang-command "^2.0.0"
435
  which "^2.0.1"
436
 
437
+ crypt@0.0.2:
438
+ version "0.0.2"
439
+ resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
440
+ integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==
441
+
442
  crypto-js@^4.1.1:
443
  version "4.2.0"
444
  resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
 
497
  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
498
  integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
499
 
500
+ digest-fetch@^1.3.0:
501
+ version "1.3.0"
502
+ resolved "https://registry.yarnpkg.com/digest-fetch/-/digest-fetch-1.3.0.tgz#898e69264d00012a23cf26e8a3e40320143fc661"
503
+ integrity sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==
504
+ dependencies:
505
+ base-64 "^0.1.0"
506
+ md5 "^2.3.0"
507
+
508
  doctrine@3.0.0, doctrine@^3.0.0:
509
  version "3.0.0"
510
  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
 
627
  resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
628
  integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
629
 
630
+ event-target-shim@^5.0.0:
631
+ version "5.0.1"
632
+ resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
633
+ integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
634
+
635
  express@^4.18.2:
636
  version "4.18.2"
637
  resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
 
743
  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
744
  integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
745
 
746
+ form-data-encoder@1.7.2:
747
+ version "1.7.2"
748
+ resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040"
749
+ integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==
750
+
751
  form-data@^4.0.0:
752
  version "4.0.0"
753
  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
 
757
  combined-stream "^1.0.8"
758
  mime-types "^2.1.12"
759
 
760
+ formdata-node@^4.3.2:
761
+ version "4.4.1"
762
+ resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2"
763
+ integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==
764
+ dependencies:
765
+ node-domexception "1.0.0"
766
+ web-streams-polyfill "4.0.0-beta.3"
767
+
768
  forwarded@0.2.0:
769
  version "0.2.0"
770
  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
 
885
  statuses "2.0.1"
886
  toidentifier "1.0.1"
887
 
888
+ humanize-ms@^1.2.1:
889
+ version "1.2.1"
890
+ resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
891
+ integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
892
+ dependencies:
893
+ ms "^2.0.0"
894
+
895
  iconv-lite@0.4.24:
896
  version "0.4.24"
897
  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
 
950
  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
951
  integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
952
 
953
+ is-buffer@~1.1.6:
954
+ version "1.1.6"
955
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
956
+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
957
+
958
  is-extglob@^2.1.1:
959
  version "2.1.1"
960
  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
 
1072
  resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4"
1073
  integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==
1074
 
1075
+ md5@^2.3.0:
1076
+ version "2.3.0"
1077
+ resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
1078
+ integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
1079
+ dependencies:
1080
+ charenc "0.0.2"
1081
+ crypt "0.0.2"
1082
+ is-buffer "~1.1.6"
1083
+
1084
  media-typer@0.3.0:
1085
  version "0.3.0"
1086
  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
 
1130
  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
1131
  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
1132
 
1133
+ ms@2.1.3, ms@^2.0.0:
1134
  version "2.1.3"
1135
  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
1136
  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
 
1145
  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
1146
  integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
1147
 
1148
+ node-domexception@1.0.0:
1149
+ version "1.0.0"
1150
+ resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
1151
+ integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
1152
+
1153
+ node-fetch@^2.6.7:
1154
+ version "2.7.0"
1155
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
1156
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
1157
+ dependencies:
1158
+ whatwg-url "^5.0.0"
1159
+
1160
  object-inspect@^1.9.0:
1161
  version "1.13.1"
1162
  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
 
1176
  dependencies:
1177
  wrappy "1"
1178
 
1179
+ openai@^4.20.1:
1180
+ version "4.20.1"
1181
+ resolved "https://registry.yarnpkg.com/openai/-/openai-4.20.1.tgz#afa0d496d125b5a0f6cebcb4b9aeabf71e00214e"
1182
+ integrity sha512-Dd3q8EvINfganZFtg6V36HjrMaihqRgIcKiHua4Nq9aw/PxOP48dhbsk8x5klrxajt5Lpnc1KTOG5i1S6BKAJA==
1183
+ dependencies:
1184
+ "@types/node" "^18.11.18"
1185
+ "@types/node-fetch" "^2.6.4"
1186
+ abort-controller "^3.0.0"
1187
+ agentkeepalive "^4.2.1"
1188
+ digest-fetch "^1.3.0"
1189
+ form-data-encoder "1.7.2"
1190
+ formdata-node "^4.3.2"
1191
+ node-fetch "^2.6.7"
1192
+ web-streams-polyfill "^3.2.1"
1193
+
1194
  optionator@^0.9.3:
1195
  version "0.9.3"
1196
  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
 
1483
  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
1484
  integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
1485
 
1486
+ tr46@~0.0.3:
1487
+ version "0.0.3"
1488
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
1489
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
1490
+
1491
  type-check@^0.4.0, type-check@~0.4.0:
1492
  version "0.4.0"
1493
  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
 
1508
  media-typer "0.3.0"
1509
  mime-types "~2.1.24"
1510
 
1511
+ undici-types@~5.26.4:
1512
+ version "5.26.5"
1513
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
1514
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
1515
+
1516
  unpipe@1.0.0, unpipe@~1.0.0:
1517
  version "1.0.0"
1518
  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
 
1540
  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
1541
  integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
1542
 
1543
+ web-streams-polyfill@4.0.0-beta.3:
1544
+ version "4.0.0-beta.3"
1545
+ resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38"
1546
+ integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==
1547
+
1548
+ web-streams-polyfill@^3.2.1:
1549
+ version "3.2.1"
1550
+ resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
1551
+ integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
1552
+
1553
+ webidl-conversions@^3.0.0:
1554
+ version "3.0.1"
1555
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
1556
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
1557
+
1558
+ whatwg-url@^5.0.0:
1559
+ version "5.0.0"
1560
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
1561
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
1562
+ dependencies:
1563
+ tr46 "~0.0.3"
1564
+ webidl-conversions "^3.0.0"
1565
+
1566
  which@^2.0.1:
1567
  version "2.0.2"
1568
  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"