sujoydev99 commited on
Commit
8ed82cb
·
1 Parent(s): 579f597
Files changed (4) hide show
  1. api.js +1783 -0
  2. netlify.tolm +9 -0
  3. package.json +3 -0
  4. yarn.lock +113 -0
api.js ADDED
@@ -0,0 +1,1783 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express, { Router } from "express";
2
+ import serverless from "serverless-http";
3
+ import Redis from "ioredis";
4
+ import { initClient } from './utils.js';
5
+ import { errorHandler, setJioCopilotSessionCookie } from './middleware.js';
6
+ import swaggerJSDoc from 'swagger-jsdoc';
7
+ import yaml from 'js-yaml'
8
+ import fs from 'fs';
9
+ import { RedisListCache } from './cache.js';
10
+ import {
11
+ getApplications,
12
+ createApplication,
13
+ getLocations,
14
+ createLocation,
15
+ updateLocation,
16
+ getBrands,
17
+ createBrand,
18
+ updateBrand,
19
+ createProduct,
20
+ createInventory,
21
+ getCompanyCreds,
22
+ createUpdateCompanyCreds
23
+ } from './functions.js'
24
+ import OpenAI from 'openai';
25
+ import compression from 'compression';
26
+ import cookieParser from 'cookie-parser';
27
+ const listCache = new RedisListCache({ namespace: "fc" })
28
+ const redis = new Redis();
29
+ const skills = {
30
+ getApplications,
31
+ createApplication,
32
+ getLocations,
33
+ createLocation,
34
+ updateLocation,
35
+ getBrands,
36
+ createBrand,
37
+ updateBrand,
38
+ createProduct,
39
+ createInventory,
40
+ getCompanyCreds,
41
+ createUpdateCompanyCreds
42
+ }
43
+ const app = express();
44
+ const router = Router();
45
+ api.use("/api/", router);
46
+ const port = process.env.PORT;
47
+ app.use(express.json({}));
48
+ const swaggerDefinition = {
49
+ openapi: '3.0.0',
50
+ info: {
51
+ title: 'Express API Documentation',
52
+ version: '1.0.0',
53
+ description: 'This is the API documentation for my Express application.'
54
+ },
55
+ servers: [{
56
+ url: "https://934a-45-119-30-178.ngrok-free.app"
57
+ }]
58
+ };
59
+ const options = {
60
+ swaggerDefinition,
61
+ // Path to the API docs
62
+ apis: ['./index.js'], // Adjust the path according to your file structure
63
+ };
64
+ app.use(compression())
65
+ app.use(cookieParser())
66
+
67
+ /**
68
+ * @swagger
69
+ * components:
70
+ * schemas:
71
+ * CompanyCreds:
72
+ * type: object
73
+ * properties:
74
+ * clientId:
75
+ * type: string
76
+ * description: Client ID for the company
77
+ * clientSecret:
78
+ * type: string
79
+ * description: Client secret for the company
80
+ * required:
81
+ * - clientId
82
+ * - clientSecret
83
+ * CreateUpdateLocation:
84
+ * type: object
85
+ * required:
86
+ * - code
87
+ * - name
88
+ * - gst
89
+ * - manager
90
+ * - address
91
+ * properties:
92
+ * code:
93
+ * type: string
94
+ * description: Unique code for the location
95
+ * name:
96
+ * type: string
97
+ * description: Name of the location
98
+ * gst:
99
+ * type: object
100
+ * required:
101
+ * - legal_name
102
+ * - value
103
+ * properties:
104
+ * legal_name:
105
+ * type: string
106
+ * description: Legal name for GST purposes
107
+ * value:
108
+ * type: string
109
+ * description: GST value
110
+ * manager:
111
+ * type: object
112
+ * required:
113
+ * - manager_name
114
+ * - email
115
+ * - number
116
+ * - country_code
117
+ * properties:
118
+ * manager_name:
119
+ * type: string
120
+ * description: Name of the manager
121
+ * email:
122
+ * type: string
123
+ * description: Email of the manager
124
+ * number:
125
+ * type: string
126
+ * description: Contact number of the manager
127
+ * country_code:
128
+ * type: string
129
+ * description: Country code for the manager's contact number
130
+ * address:
131
+ * type: object
132
+ * required:
133
+ * - address1
134
+ * - country
135
+ * - pincode
136
+ * - city
137
+ * - state
138
+ * properties:
139
+ * address1:
140
+ * type: string
141
+ * description: Primary address line
142
+ * address2:
143
+ * type: string
144
+ * description: Secondary address line
145
+ * country:
146
+ * type: string
147
+ * description: Country of the location
148
+ * pincode:
149
+ * type: string
150
+ * description: Postal code of the location
151
+ * city:
152
+ * type: string
153
+ * description: City of the location
154
+ * state:
155
+ * type: string
156
+ * description: State of the location
157
+ * latitude:
158
+ * type: number
159
+ * description: Latitude for the location
160
+ * longitude:
161
+ * type: number
162
+ * description: Longitude for the location
163
+ * landmark:
164
+ * type: string
165
+ * description: Landmark near the location
166
+ * Brand:
167
+ * type: object
168
+ * properties:
169
+ * name:
170
+ * type: string
171
+ * logo:
172
+ * type: string
173
+ * id:
174
+ * type: string
175
+ * BrandCreation:
176
+ * type: object
177
+ * required:
178
+ * - name
179
+ * - logo
180
+ * - description
181
+ * properties:
182
+ * name:
183
+ * type: string
184
+ * logo:
185
+ * type: string
186
+ * description:
187
+ * type: string
188
+ * ErrorResponse:
189
+ * type: object
190
+ * properties:
191
+ * message:
192
+ * type: string
193
+ * description: Error message
194
+ */
195
+
196
+ router.get(['/swagger.yaml', '/swagger.json'], (req, res) => {
197
+ // Initialize swagger-jsdoc
198
+ const swaggerSpec = swaggerJSDoc(options);
199
+
200
+ // Convert to YAML
201
+ const swaggerYAML = yaml.dump(swaggerSpec);
202
+ switch (req.path.split('.').pop()) {
203
+ case 'json':
204
+ res.setHeader('Content-Type', 'application/json');
205
+ return res.send(JSON.stringify(swaggerSpec, null, 2));
206
+ case 'yaml':
207
+ res.setHeader('Content-Type', 'text/yaml');
208
+ return res.send(swaggerYAML);
209
+ }
210
+ });
211
+
212
+ /**
213
+ * @swagger
214
+ * /_healthz:
215
+ * get:
216
+ * operationId: getHealthZ
217
+ * description: Check server health
218
+ * responses:
219
+ * 200:
220
+ * description: Server is healthy
221
+ * content:
222
+ * text/plain:
223
+ * schema:
224
+ * type: string
225
+ * example: Hello World!
226
+ */
227
+ router.get("/_healthz", (req, res) => {
228
+ res.send('Hello World!');
229
+ });
230
+ router.get("/privacy", (req, res) => {
231
+ res.send('This is the privacy policy page!');
232
+ });
233
+
234
+ /**
235
+ * @swagger
236
+ * /company/{companyId}:
237
+ * get:
238
+ * operationId: getOrVerifyCompanyCredentials
239
+ * description: Retrieve company credentials
240
+ * tags: [Company]
241
+ * parameters:
242
+ * - in: path
243
+ * name: companyId
244
+ * required: true
245
+ * schema:
246
+ * type: string
247
+ * description: The company ID
248
+ * responses:
249
+ * 200:
250
+ * description: Company credentials retrieved successfully
251
+ * content:
252
+ * application/json:
253
+ * schema:
254
+ * $ref: '#/components/schemas/CompanyCreds'
255
+ * 404:
256
+ * description: Company credentials not found
257
+ * content:
258
+ * application/json:
259
+ * schema:
260
+ * $ref: '#/components/schemas/ErrorResponse'
261
+ */
262
+ router.get("/company/:companyId", async (req, res, next) => {
263
+ try {
264
+ const { companyId } = req.params;
265
+ const creds = await redis.get(`${companyId}:creds`);
266
+ if (!creds) {
267
+ throw {
268
+ message: "company creds not found"
269
+ }
270
+ }
271
+ res.json({ ...JSON.parse(creds), companyId })
272
+ } catch (e) {
273
+ next(e)
274
+ }
275
+ })
276
+
277
+ /**
278
+ * @swagger
279
+ * /company/{companyId}:
280
+ * put:
281
+ * operationId: updateCompanyCredentials
282
+ * description: Update company credentials
283
+ * tags: [Company]
284
+ * parameters:
285
+ * - in: path
286
+ * name: companyId
287
+ * required: true
288
+ * schema:
289
+ * type: string
290
+ * description: The company ID
291
+ * requestBody:
292
+ * required: true
293
+ * content:
294
+ * application/json:
295
+ * schema:
296
+ * $ref: '#/components/schemas/CompanyCreds'
297
+ * responses:
298
+ * 200:
299
+ * description: Company credentials updated successfully
300
+ * content:
301
+ * application/json:
302
+ * schema:
303
+ * type: object
304
+ * properties:
305
+ * message:
306
+ * type: string
307
+ * 400:
308
+ * description: Invalid input
309
+ * content:
310
+ * application/json:
311
+ * schema:
312
+ * $ref: '#/components/schemas/ErrorResponse'
313
+ */
314
+ router.put("/company/:companyId", async (req, res, next) => {
315
+ try {
316
+ const { companyId } = req.params;
317
+ const { clientId, clientSecret } = req.body
318
+ const creds = await redis.set(`${companyId}:creds`, JSON.stringify({ clientId, clientSecret }));
319
+ res.json({ message: "company creds saved" })
320
+ } catch (e) {
321
+ next(e)
322
+ }
323
+ })
324
+
325
+
326
+
327
+ /**
328
+ * @swagger
329
+ * /company/{companyId}/applications:
330
+ * get:
331
+ * operationId: getSalesChannelByCompany
332
+ * description: Retrieve applications for a specific company
333
+ * tags: [Company]
334
+ * parameters:
335
+ * - in: path
336
+ * name: companyId
337
+ * required: true
338
+ * schema:
339
+ * type: string
340
+ * description: The ID of the company to retrieve applications for
341
+ * responses:
342
+ * 200:
343
+ * description: List of applications for the specified company
344
+ * content:
345
+ * application/json:
346
+ * schema:
347
+ * type: array
348
+ * items:
349
+ * type: object
350
+ * properties:
351
+ * name:
352
+ * type: string
353
+ * description: Name of the application
354
+ * id:
355
+ * type: string
356
+ * description: ID of the application
357
+ * token:
358
+ * type: string
359
+ * description: Token associated with the application
360
+ * domain:
361
+ * type: string
362
+ * description: Primary domain of the application
363
+ * logo:
364
+ * type: string
365
+ * description: Logo URL of the application
366
+ * 500:
367
+ * description: Server error
368
+ * content:
369
+ * application/json:
370
+ * schema:
371
+ * $ref: '#/components/schemas/ErrorResponse'
372
+ */
373
+ router.get("/company/:companyId/applications", async (req, res, next) => {
374
+ try {
375
+ const { companyId } = req.params;
376
+ const client = await initClient(companyId);
377
+ let applications = await client.configuration.getApplications({ pageSize: 100 });
378
+ applications = applications.items.map(i => {
379
+ return {
380
+ name: i.name,
381
+ id: i.id,
382
+ token: i.token,
383
+ domain: i.domains?.find(i => i.is_primary)?.name,
384
+ logo: i.logo?.secure_url
385
+ }
386
+ })
387
+ res.json(applications)
388
+ } catch (e) {
389
+ next(e)
390
+ }
391
+ })
392
+
393
+ /**
394
+ * @swagger
395
+ * /company/{companyId}/brands:
396
+ * get:
397
+ * summary: Retrieves a list of brands for a specific company
398
+ * tags: [Brands]
399
+ * operationId: getCompanyBrands
400
+ * description: Fetches a list of brands associated with the given company ID.
401
+ * parameters:
402
+ * - in: path
403
+ * name: companyId
404
+ * required: true
405
+ * schema:
406
+ * type: string
407
+ * description: The unique identifier of the company
408
+ * responses:
409
+ * 200:
410
+ * description: A list of brands
411
+ * content:
412
+ * application/json:
413
+ * schema:
414
+ * type: array
415
+ * items:
416
+ * $ref: '#/components/schemas/Brand'
417
+ */
418
+ router.get("/company/:companyId/brands", async (req, res, next) => {
419
+ try {
420
+ const { companyId } = req.params;
421
+ const client = await initClient(companyId);
422
+ let brands = await client.companyProfile.getBrands({ pageSize: 300 });
423
+ brands = brands.items.map(i => {
424
+ return {
425
+ name: i?.brand?.name,
426
+ logo: i?.brand?.logo,
427
+ id: i?.brand?.uid,
428
+ }
429
+ })
430
+ res.json(brands)
431
+ } catch (e) {
432
+ next(e)
433
+ }
434
+ })
435
+
436
+ /**
437
+ * @swagger
438
+ * /company/{companyId}/brands:
439
+ * post:
440
+ * summary: Creates a new brand for a specific company
441
+ * tags: [Brands]
442
+ * operationId: createCompanyBrand
443
+ * description: Adds a new brand to the company profile.
444
+ * parameters:
445
+ * - in: path
446
+ * name: companyId
447
+ * required: true
448
+ * schema:
449
+ * type: string
450
+ * description: The unique identifier of the company
451
+ * requestBody:
452
+ * required: true
453
+ * content:
454
+ * application/json:
455
+ * schema:
456
+ * $ref: '#/components/schemas/BrandCreation'
457
+ * responses:
458
+ * 200:
459
+ * description: Brand created successfully
460
+ * content:
461
+ * application/json:
462
+ * schema:
463
+ * type: object
464
+ * properties:
465
+ * message:
466
+ * type: string
467
+ * id:
468
+ * type: string
469
+ *
470
+ * /company/{companyId}/brands/{brandId}:
471
+ * put:
472
+ * summary: Creates a new brand for a specific company
473
+ * tags: [Brands]
474
+ * operationId: updateCompanyBrand
475
+ * description: updated an existing brand.
476
+ * parameters:
477
+ * - in: path
478
+ * name: companyId
479
+ * required: true
480
+ * schema:
481
+ * type: string
482
+ * description: The unique identifier of the company
483
+ * - in: path
484
+ * name: brandId
485
+ * required: true
486
+ * schema:
487
+ * type: number
488
+ * description: The unique identifier of the brand
489
+ * requestBody:
490
+ * required: true
491
+ * content:
492
+ * application/json:
493
+ * schema:
494
+ * $ref: '#/components/schemas/BrandCreation'
495
+ * responses:
496
+ * 200:
497
+ * description: Brand updated successfully
498
+ * content:
499
+ * application/json:
500
+ * schema:
501
+ * type: object
502
+ * properties:
503
+ * message:
504
+ * type: string
505
+ * id:
506
+ * type: string
507
+ */
508
+ router.post("/company/:companyId/brands", async (req, res, next) => {
509
+ try {
510
+ const { companyId } = req.params;
511
+ const client = await initClient(companyId);
512
+ const {
513
+ name,
514
+ logo = "https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/fyprod/wrkr/platform/pictures/favicon/original/ZWTmgEoFQ-platform-favicon.png",
515
+ description
516
+ } = req.body
517
+ let brands = await client.companyProfile.createBrand({
518
+ body: {
519
+ name,
520
+ description,
521
+ logo,
522
+ banner: { portrait: logo, landscape: logo }
523
+ }
524
+ });
525
+ res.json({ message: "brand created", id: brands?.uid })
526
+ } catch (e) {
527
+ next(e)
528
+ }
529
+ })
530
+ router.put("/company/:companyId/brands/:brandId", async (req, res, next) => {
531
+ try {
532
+ const { companyId, brandId } = req.params;
533
+ const client = await initClient(companyId);
534
+ const {
535
+ name,
536
+ logo = "https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/fyprod/wrkr/platform/pictures/favicon/original/ZWTmgEoFQ-platform-favicon.png",
537
+ description
538
+ } = req.body
539
+ let brands = await client.companyProfile.editBrand({
540
+ brandId,
541
+ body: {
542
+ name,
543
+ description,
544
+ logo,
545
+ banner: { portrait: logo, landscape: logo }
546
+ }
547
+ });
548
+ res.json({ message: "brand updated", id: brands?.id })
549
+ } catch (e) {
550
+ next(e)
551
+ }
552
+ })
553
+
554
+ /**
555
+ * @swagger
556
+ * /company/{companyId}/locations:
557
+ * get:
558
+ * operationId: getLocationsByCompany
559
+ * description: get all company locations
560
+ * tags: [Company]
561
+ * parameters:
562
+ * - in: path
563
+ * name: companyId
564
+ * required: true
565
+ * schema:
566
+ * type: string
567
+ * description: The ID of the company to add a location for
568
+ * responses:
569
+ * 200:
570
+ * description: location list
571
+ * content:
572
+ * application/json:
573
+ * schema:
574
+ * type: array
575
+ * items:
576
+ * properties:
577
+ * id:
578
+ * type: number
579
+ * description: Location id
580
+ * code:
581
+ * type: string
582
+ * description: Location code
583
+ * name:
584
+ * type: string
585
+ * description: Location code
586
+ * documents:
587
+ * type: array
588
+ * description: Location gst documents
589
+ * items:
590
+ * type: object
591
+ * properties:
592
+ * type:
593
+ * type: string
594
+ * description: document type
595
+ * value:
596
+ * type: string
597
+ * description: document number
598
+ * verified:
599
+ * type: boolean
600
+ * description: document number verification status
601
+ * legal_name:
602
+ * type: boolean
603
+ * description: document owner
604
+ * 400:
605
+ * description: Invalid input
606
+ * content:
607
+ * application/json:
608
+ * schema:
609
+ * $ref: '#/components/schemas/ErrorResponse'
610
+ */
611
+ router.get("/company/:companyId/locations", async (req, res, next) => {
612
+ try {
613
+ const { companyId } = req.params;
614
+ const client = await initClient(companyId.toString());
615
+ let locations = await client.companyProfile.getLocations({ pageSize: 100 });
616
+ locations = locations.items.map(i => {
617
+ return {
618
+ name: i.name,
619
+ id: i.uid,
620
+ code: i.code,
621
+ documents: i.documents
622
+ }
623
+ })
624
+ res.json(locations)
625
+ } catch (e) {
626
+ next(e)
627
+ }
628
+ })
629
+ /**
630
+ * @swagger
631
+ * /company/{companyId}/locations:
632
+ * post:
633
+ * operationId: createLocationsForCompany
634
+ * description: Add a new location for a specific company
635
+ * tags: [Company]
636
+ * parameters:
637
+ * - in: path
638
+ * name: companyId
639
+ * required: true
640
+ * schema:
641
+ * type: string
642
+ * description: The ID of the company to add a location for
643
+ * requestBody:
644
+ * required: true
645
+ * content:
646
+ * application/json:
647
+ * schema:
648
+ * $ref: '#/components/schemas/CreateUpdateLocation'
649
+ * responses:
650
+ * 200:
651
+ * description: Location created successfully
652
+ * content:
653
+ * application/json:
654
+ * schema:
655
+ * type: object
656
+ * properties:
657
+ * message:
658
+ * type: string
659
+ * id:
660
+ * type: string
661
+ * description: Location id
662
+ * 400:
663
+ * description: Invalid input
664
+ * content:
665
+ * application/json:
666
+ * schema:
667
+ * $ref: '#/components/schemas/ErrorResponse'
668
+ * /company/{companyId}/locations/{locationId}:
669
+ * put:
670
+ * operationId: updateLocationByCompany
671
+ * description: update a location for a specific company
672
+ * tags: [Company]
673
+ * parameters:
674
+ * - in: path
675
+ * name: companyId
676
+ * required: true
677
+ * schema:
678
+ * type: string
679
+ * description: The ID of the company to add a location for
680
+ * - in: path
681
+ * name: locationId
682
+ * required: true
683
+ * schema:
684
+ * type: string
685
+ * description: The ID of the location to be updated
686
+ * requestBody:
687
+ * required: true
688
+ * content:
689
+ * application/json:
690
+ * schema:
691
+ * $ref: '#/components/schemas/CreateUpdateLocation'
692
+ * responses:
693
+ * 200:
694
+ * description: Location updated successfully
695
+ * content:
696
+ * application/json:
697
+ * schema:
698
+ * type: object
699
+ * properties:
700
+ * message:
701
+ * type: string
702
+ * id:
703
+ * type: string
704
+ * description: Location id
705
+ * 400:
706
+ * description: Invalid input
707
+ * content:
708
+ * application/json:
709
+ * schema:
710
+ * $ref: '#/components/schemas/ErrorResponse'
711
+ */
712
+ router.post("/company/:companyId/locations", async (req, res, next) => {
713
+ try {
714
+ const { companyId } = req.params;
715
+ const { code,
716
+ name,
717
+ gst: {
718
+ legal_name,
719
+ value
720
+ },
721
+ manager: {
722
+ manager_name, email, number, country_code
723
+ },
724
+ address: {
725
+ address1,
726
+ address2,
727
+ country,
728
+ pincode,
729
+ city,
730
+ state,
731
+ latitude = 19.2762702,
732
+ longitude = 72.8929,
733
+ landmark = ""
734
+ },
735
+
736
+ } = req.body
737
+ const client = await initClient(companyId);
738
+ let locations = await client.companyProfile.createLocation({
739
+ body: {
740
+ name,
741
+ display_name: name,
742
+ code,
743
+ company: parseInt(companyId),
744
+ documents: [{
745
+ type: "gst",
746
+ legal_name: legal_name,
747
+ value: value, verified: true
748
+ }],
749
+ address: {
750
+ "address1": address1,
751
+ "address2": address2,
752
+ "country": country,
753
+ "pincode": pincode,
754
+ "city": city,
755
+ "state": state,
756
+ "latitude": latitude,
757
+ "longitude": longitude,
758
+ "landmark": landmark
759
+ },
760
+ manager: {
761
+ "name": manager_name,
762
+ "email": email,
763
+ "mobile_no": {
764
+ "number": number,
765
+ "country_code": country_code
766
+ }
767
+ },
768
+ contact_numbers: [
769
+ {
770
+ "number": number,
771
+ "country_code": country_code
772
+ }
773
+ ],
774
+ store_type: "high_street"
775
+
776
+ }
777
+ });
778
+
779
+ res.json({ message: "location added", id: locations?.uid })
780
+ } catch (e) {
781
+ next(e)
782
+ }
783
+ })
784
+ router.put("/company/:companyId/locations/locationId", async (req, res, next) => {
785
+ try {
786
+ const { companyId } = req.params;
787
+ const { code,
788
+ name,
789
+ gst: {
790
+ legal_name,
791
+ value
792
+ },
793
+ manager: {
794
+ manager_name, email, number, country_code
795
+ },
796
+ address: {
797
+ address1,
798
+ address2,
799
+ country,
800
+ pincode,
801
+ city,
802
+ state,
803
+ latitude = 19.2762702,
804
+ longitude = 72.8929,
805
+ landmark = ""
806
+ },
807
+
808
+ } = req.body
809
+ const client = await initClient(companyId);
810
+ let locations = await client.companyProfile.createLocation({
811
+ body: {
812
+ name,
813
+ display_name: name,
814
+ code,
815
+ company: parseInt(companyId),
816
+ documents: [{
817
+ type: "gst",
818
+ legal_name: legal_name,
819
+ value: value, verified: true
820
+ }],
821
+ address: {
822
+ "address1": address1,
823
+ "address2": address2,
824
+ "country": country,
825
+ "pincode": pincode,
826
+ "city": city,
827
+ "state": state,
828
+ "latitude": latitude,
829
+ "longitude": longitude,
830
+ "landmark": landmark
831
+ },
832
+ manager: {
833
+ "name": manager_name,
834
+ "email": email,
835
+ "mobile_no": {
836
+ "number": number,
837
+ "country_code": country_code
838
+ }
839
+ },
840
+ contact_numbers: [
841
+ {
842
+ "number": number,
843
+ "country_code": country_code
844
+ }
845
+ ],
846
+ store_type: "high_street"
847
+
848
+ }
849
+ });
850
+
851
+ res.json({ message: "location updated", id: locations?.id })
852
+ } catch (e) {
853
+ next(e)
854
+ }
855
+ })
856
+
857
+
858
+
859
+ /**
860
+ * @swagger
861
+ * /company/{companyId}/products:
862
+ * post:
863
+ * summary: Creates a new product for a given company.
864
+ * description: This endpoint creates a new product with various attributes including name, slug, pricing, and more.
865
+ * operationId: createProduct
866
+ * tags:
867
+ * - Products
868
+ * parameters:
869
+ * - in: path
870
+ * name: companyId
871
+ * required: true
872
+ * schema:
873
+ * type: string
874
+ * description: Unique identifier of the company.
875
+ * requestBody:
876
+ * required: true
877
+ * content:
878
+ * application/json:
879
+ * schema:
880
+ * type: object
881
+ * required:
882
+ * - name
883
+ * - slug
884
+ * - seller_identifier
885
+ * - brand_id
886
+ * properties:
887
+ * name:
888
+ * type: string
889
+ * description: Name of the product.
890
+ * slug:
891
+ * type: string
892
+ * description: URL-friendly identifier for the product.
893
+ * seller_identifier:
894
+ * type: string
895
+ * description: Unique identifier for the seller.
896
+ * brand_id:
897
+ * type: string
898
+ * description: Unique identifier for the brand.
899
+ * location_id:
900
+ * type: string
901
+ * description: Location identifier for the product.
902
+ * mrp:
903
+ * type: number
904
+ * default: 999
905
+ * description: Maximum retail price of the product.
906
+ * selling_price:
907
+ * type: number
908
+ * default: 499
909
+ * description: Selling price of the product.
910
+ * responses:
911
+ * 200:
912
+ * description: Successful creation of the product.
913
+ * content:
914
+ * application/json:
915
+ * schema:
916
+ * type: object
917
+ * properties:
918
+ * message:
919
+ * type: string
920
+ * id:
921
+ * type: string
922
+ * seller_identifier:
923
+ * type: string
924
+ */
925
+
926
+ router.post("/company/:companyId/products", async (req, res, next) => {
927
+ try {
928
+ const { companyId } = req.params;
929
+ const { name,
930
+ slug,
931
+ seller_identifier,
932
+ brand_id, location_id, mrp = 999, selling_price = 499
933
+ } = req.body;
934
+ const obj = {
935
+ "name": name,
936
+ "slug": slug,
937
+ "brand_uid": brand_id,
938
+ "item_code": seller_identifier,
939
+ "teaser_tag": {},
940
+ "net_quantity": {},
941
+ "tax_identifier": {
942
+ "reporting_hsn": "1202355241H1",
943
+ "hsn_code": "1202355241",
944
+ "hsn_code_id": "65769883ba99dcf407a2b1ed"
945
+ },
946
+ "country_of_origin": "India",
947
+ "variants": {},
948
+ "variant_media": {},
949
+ "description": "PHA+WW91ciBwcm9kdWN0IGRlc2NyaXB0aW9uPC9wPg==",
950
+ "short_description": "Your product description",
951
+ "highlights": [],
952
+ "company_id": 10,
953
+ "template_tag": "c2-0-template",
954
+ "currency": "INR",
955
+ "media": [],
956
+ "is_set": false,
957
+ "sizes": [
958
+ {
959
+ "size": "OS",
960
+ "price": mrp,
961
+ "price_effective": selling_price,
962
+ "price_transfer": 0,
963
+ "currency": "INR",
964
+ "item_length": 1,
965
+ "item_width": 1,
966
+ "item_height": 1,
967
+ "item_weight": 1,
968
+ "item_dimensions_unit_of_measure": "cm",
969
+ "item_weight_unit_of_measure": "gram",
970
+ "track_inventory": true,
971
+ "identifiers": [
972
+ {
973
+ "gtin_value": seller_identifier,
974
+ "gtin_type": "ean",
975
+ "primary": true
976
+ }
977
+ ],
978
+ "_custom_json": {},
979
+ "name": "OS"
980
+ }
981
+ ],
982
+ "_custom_json": {},
983
+ "size_guide": "",
984
+ "product_group_tag": [],
985
+ "product_publish": {
986
+ "product_online_date": "2023-12-11T08:38:10.082Z",
987
+ "is_set": false
988
+ },
989
+ "is_active": true,
990
+ "custom_order": {
991
+ "is_custom_order": false,
992
+ "manufacturing_time": 0,
993
+ "manufacturing_time_unit": "hours"
994
+ },
995
+ "multi_size": false,
996
+ "no_of_boxes": 1,
997
+ "is_dependent": false,
998
+ "item_type": "digital",
999
+ "tags": [],
1000
+ "departments": [
1001
+ 19771
1002
+ ],
1003
+ return_config: {
1004
+ "returnable": false
1005
+ },
1006
+ "category_slug": "c2-0-cat",
1007
+ "trader": [
1008
+ {
1009
+ "type": "Manufacturer",
1010
+ "name": "Manufacturer",
1011
+ "address": [
1012
+ "Manufacturer Address"
1013
+ ]
1014
+ }
1015
+ ],
1016
+ "return_config": {
1017
+ "returnable": true,
1018
+ time: 3,
1019
+ unit: "days"
1020
+ }
1021
+ }
1022
+ const client = await initClient(companyId);
1023
+ let product = await client.catalog.createProduct({
1024
+ body: obj
1025
+ });
1026
+ product = await client.catalog.getProduct({
1027
+ itemId: product.uid
1028
+ });
1029
+ res.json({
1030
+ message: "product created",
1031
+ id: product.data.uid,
1032
+ seller_identifier: product?.data?.sizes?.[0]?.seller_identifier
1033
+ });
1034
+ } catch (e) { next(e) }
1035
+ })
1036
+
1037
+ /**
1038
+ * @swagger
1039
+ * /company/{companyId}/products/{productId}/inventory:
1040
+ * post:
1041
+ * summary: Updates inventory for a specific product.
1042
+ * description: This endpoint updates the inventory details for a given product, including location, pricing, and quantity.
1043
+ * operationId: updateInventory
1044
+ * tags:
1045
+ * - Inventory
1046
+ * parameters:
1047
+ * - in: path
1048
+ * name: companyId
1049
+ * required: true
1050
+ * schema:
1051
+ * type: string
1052
+ * description: Unique identifier of the company.
1053
+ * - in: path
1054
+ * name: productId
1055
+ * required: true
1056
+ * schema:
1057
+ * type: string
1058
+ * description: Unique identifier of the product.
1059
+ * requestBody:
1060
+ * required: true
1061
+ * content:
1062
+ * application/json:
1063
+ * schema:
1064
+ * type: object
1065
+ * required:
1066
+ * - location_id
1067
+ * - seller_identifier
1068
+ * properties:
1069
+ * location_id:
1070
+ * type: string
1071
+ * description: Location identifier where the inventory is stored.
1072
+ * mrp:
1073
+ * type: number
1074
+ * default: 999
1075
+ * description: Maximum retail price of the product.
1076
+ * selling_price:
1077
+ * type: number
1078
+ * default: 499
1079
+ * description: Selling price of the product.
1080
+ * seller_identifier:
1081
+ * type: string
1082
+ * description: Unique identifier for the seller.
1083
+ * responses:
1084
+ * 200:
1085
+ * description: Successful update of inventory.
1086
+ * content:
1087
+ * application/json:
1088
+ * schema:
1089
+ * type: object
1090
+ * properties:
1091
+ * message:
1092
+ * type: string
1093
+ */
1094
+ router.post("/company/:companyId/products/:productId/inventory", async (req, res, next) => {
1095
+ try {
1096
+ const { companyId, productId } = req.params;
1097
+ const { location_id, mrp = 999, selling_price = 499, id, seller_identifier } = req.body;
1098
+ const client = await initClient(companyId);
1099
+ let product = await client.catalog.getProduct({
1100
+ itemId: productId
1101
+ });
1102
+ let inv = await client.catalog.updateRealtimeInventory({
1103
+ itemId: product.data.uid,
1104
+ sellerIdentifier: seller_identifier,
1105
+ body: {
1106
+ company_id: companyId,
1107
+ payload: [{
1108
+ "seller_identifier": seller_identifier,
1109
+ "store_id": location_id,
1110
+ "price_marked": mrp,
1111
+ "price_effective": selling_price,
1112
+ "total_quantity": 10,
1113
+ "tags": []
1114
+ }]
1115
+ }
1116
+ })
1117
+
1118
+ res.json({ message: "inv created" });
1119
+ } catch (e) { next(e) }
1120
+ })
1121
+
1122
+
1123
+ /**
1124
+ * @swagger
1125
+ * /company/{companyId}/sales_channel:
1126
+ * post:
1127
+ * operationId: addSalesChannel
1128
+ * summary: Create a sales channel for a given company
1129
+ * description: This endpoint creates a new sales channel for the specified company.
1130
+ * tags:
1131
+ * - Sales Channel
1132
+ * parameters:
1133
+ * - in: path
1134
+ * name: companyId
1135
+ * required: true
1136
+ * schema:
1137
+ * type: string
1138
+ * description: The ID of the company
1139
+ * requestBody:
1140
+ * required: true
1141
+ * content:
1142
+ * application/json:
1143
+ * schema:
1144
+ * type: object
1145
+ * properties:
1146
+ * brand_ids:
1147
+ * type: array
1148
+ * items:
1149
+ * type: integer
1150
+ * description: Array of brand IDs to be associated with the sales channel
1151
+ * name:
1152
+ * type: string
1153
+ * description: Name of the sales channel
1154
+ * subdomain:
1155
+ * type: string
1156
+ * description: subdomain associated with the sales channel
1157
+ * responses:
1158
+ * 200:
1159
+ * description: Sales channel successfully created
1160
+ * content:
1161
+ * application/json:
1162
+ * schema:
1163
+ * type: object
1164
+ * properties:
1165
+ * message:
1166
+ * type: string
1167
+ * app:
1168
+ * type: object
1169
+ * description: Details of the created sales channel
1170
+ * 400:
1171
+ * description: Bad request
1172
+ * 500:
1173
+ * description: Internal server error
1174
+ */
1175
+
1176
+ app.post("/company/:companyId/sales_channel", async (req, res, next) => {
1177
+ try {
1178
+ const { companyId } = req.params;
1179
+ const { brand_ids, name, subdomain } = req.body;
1180
+ const client = await initClient(companyId);
1181
+
1182
+ let app = await client.configuration.createApplication({
1183
+ body: {
1184
+ "app": {
1185
+ "company_id": (1).toString(),
1186
+ "channel_type": "website-and-mobile-apps",
1187
+ "auth": {
1188
+ "enabled": true
1189
+ },
1190
+ "name": name,
1191
+ "desc": "",
1192
+ "mode": "live"
1193
+ },
1194
+ "configuration": {
1195
+ "inventory": {
1196
+ "brand": {
1197
+ "criteria": "all",
1198
+ "brands": []
1199
+ },
1200
+ "store": {
1201
+ "criteria": "filter",
1202
+ "rules": [
1203
+ {
1204
+ "companies": [companyId],
1205
+ "brands": brand_ids
1206
+ }
1207
+ ],
1208
+ "stores": []
1209
+ },
1210
+ "image": ["standard", "substandard", "default"],
1211
+ "franchise_enabled": false,
1212
+ "out_of_stock": true
1213
+ },
1214
+ "payment": {
1215
+ "mode_of_payment": "ECOMM",
1216
+ "source": "ECOMM"
1217
+ },
1218
+ "article_assignment": {
1219
+ "post_order_reassignment": true,
1220
+ "enforced_stores": [],
1221
+ "rules": {
1222
+ "store_priority": {
1223
+ "enabled": false,
1224
+ "storetype_order": []
1225
+ }
1226
+ }
1227
+ }
1228
+ },
1229
+ "domain": {
1230
+ "name": `${subdomain}.hostx5.de`
1231
+ }
1232
+ }
1233
+ })
1234
+
1235
+ res.json({ message: "inv created", app });
1236
+ } catch (e) { next(e) }
1237
+ })
1238
+
1239
+ const chatHtml = fs.readFileSync('./chat.html', 'utf-8');
1240
+
1241
+ app.get('/', async (req, res, next) => {
1242
+ try {
1243
+ res.send(chatHtml);
1244
+ } catch (error) {
1245
+ console.error(error);
1246
+ res.send('Something needs to be fixed!');
1247
+ }
1248
+ });
1249
+
1250
+ app.get('/talk', async (req, res, next) => {
1251
+ try {
1252
+ res.send(chatHtml);
1253
+ } catch (error) {
1254
+ console.error(error);
1255
+ res.send('Something needs to be fixed!');
1256
+ }
1257
+ });
1258
+ app.get('/history', setJioCopilotSessionCookie, async (req, res) => {
1259
+ const session = req.jio_copilot_anonymous_session;
1260
+ let messages = [];
1261
+ if (session) {
1262
+ messages = await listCache.getAll(session);
1263
+ }
1264
+ messages = messages.filter(message => message.role === 'user' || message.role === 'assistant');
1265
+ res.json([{ role: 'assistant', content: 'Greetings! I\'m Jio Copilot, your digital aid for Jio platforms like TiraBeauty, JioCinema, JioMart, and JioFiber. Here to help with shopping, product exploration, content streaming, and internet/data plan navigation. How may I assist you today?' }, ...messages]);
1266
+ });
1267
+
1268
+ app.delete('/history', setJioCopilotSessionCookie, async (req, res) => {
1269
+ const session = req.jio_copilot_anonymous_session;
1270
+ if (session) {
1271
+ await listCache.clear(session);
1272
+ }
1273
+ res.json({ success: true });
1274
+ });
1275
+
1276
+ router.post(
1277
+ '/openai', setJioCopilotSessionCookie,
1278
+ async (req, res, next) => {
1279
+ const functions = [
1280
+ {
1281
+ "name": "getCompanyCreds",
1282
+ "description": "Retrieves credentials for a specific company based on its ID.",
1283
+ "parameters": {
1284
+ "type": "object",
1285
+ "properties": {
1286
+ "company_id": {
1287
+ "type": "number",
1288
+ "description": "Unique identifier of the company."
1289
+ }
1290
+ },
1291
+ "required": ["company_id"]
1292
+ }
1293
+ }, {
1294
+ "name": "createUpdateCompanyCreds",
1295
+ "description": "Creates or updates credentials for a company.",
1296
+ "parameters": {
1297
+ "type": "object",
1298
+ "properties": {
1299
+ "company_id": {
1300
+ "type": "number",
1301
+ "description": "Unique identifier of the company."
1302
+ },
1303
+ "clientId": {
1304
+ "type": "string",
1305
+ "description": "Client ID for authentication."
1306
+ },
1307
+ "clientSecret": {
1308
+ "type": "string",
1309
+ "description": "Client secret for authentication."
1310
+ }
1311
+ },
1312
+ "required": ["company_id", "clientId", "clientSecret"]
1313
+ }
1314
+ }, {
1315
+ "name": "getApplications",
1316
+ "description": "Retrieves a list of applications associated with a specific company ID.",
1317
+ "parameters": {
1318
+ "type": "object",
1319
+ "properties": {
1320
+ "company_id": {
1321
+ "type": "number",
1322
+ "description": "Unique identifier of the company."
1323
+ }
1324
+ },
1325
+ "required": ["company_id"]
1326
+ }
1327
+ }, {
1328
+ "name": "createBrand",
1329
+ "description": "Creates a new brand under a specific company.",
1330
+ "parameters": {
1331
+ "type": "object",
1332
+ "properties": {
1333
+ "company_id": {
1334
+ "type": "number",
1335
+ "description": "Unique identifier of the company."
1336
+ },
1337
+ "name": {
1338
+ "type": "string",
1339
+ "description": "Name of the new brand."
1340
+ },
1341
+ "description": {
1342
+ "type": "string",
1343
+ "description": "Description of the new brand."
1344
+ },
1345
+ "logo": {
1346
+ "type": "string",
1347
+ "description": "URL of the brand's logo."
1348
+ }
1349
+ },
1350
+ "required": ["company_id", "name", "description"]
1351
+ }
1352
+ }, {
1353
+ "name": "updateBrand",
1354
+ "description": "Updates the details of an existing brand within a company.",
1355
+ "parameters": {
1356
+ "type": "object",
1357
+ "properties": {
1358
+ "company_id": {
1359
+ "type": "number",
1360
+ "description": "Unique identifier of the company."
1361
+ },
1362
+ "brand_id": {
1363
+ "type": "string",
1364
+ "description": "Unique identifier of the brand to be updated."
1365
+ },
1366
+ "name": {
1367
+ "type": "string",
1368
+ "description": "New name for the brand."
1369
+ },
1370
+ "description": {
1371
+ "type": "string",
1372
+ "description": "New description for the brand."
1373
+ },
1374
+ "logo": {
1375
+ "type": "string",
1376
+ "description": "New URL for the brand's logo."
1377
+ },
1378
+ },
1379
+ "required": ["company_id", "brand_id", "name", "description"]
1380
+ }
1381
+ }, {
1382
+ "name": "getBrands",
1383
+ "description": "Retrieves a list of all brands associated with a specific company.",
1384
+ "parameters": {
1385
+ "type": "object",
1386
+ "properties": {
1387
+ "company_id": {
1388
+ "type": "number",
1389
+ "description": "Unique identifier of the company for which brands are being retrieved."
1390
+ }
1391
+ },
1392
+ "required": ["company_id"]
1393
+ }
1394
+ }, {
1395
+ "name": "getLocations",
1396
+ "description": "Retrieves a list of all locations associated with a specific company.",
1397
+ "parameters": {
1398
+ "type": "object",
1399
+ "properties": {
1400
+ "company_id": {
1401
+ "type": "number",
1402
+ "description": "Unique identifier of the company for which locations are being retrieved."
1403
+ }
1404
+ },
1405
+ "required": ["company_id"]
1406
+ }
1407
+ }, {
1408
+ "name": "createLocation",
1409
+ "description": "Creates a new location for a specified company.",
1410
+ "parameters": {
1411
+ "type": "object",
1412
+ "properties": {
1413
+ "name": {
1414
+ "type": "string",
1415
+ "description": "name of the location."
1416
+ },
1417
+ "code": {
1418
+ "type": "string",
1419
+ "description": "a unique code name."
1420
+ },
1421
+ "company_id": {
1422
+ "type": "number",
1423
+ "description": "Unique identifier of the company."
1424
+ },
1425
+ "address1": {
1426
+ "type": "string",
1427
+ "description": "Primary address line of the new location."
1428
+ },
1429
+ "address2": {
1430
+ "type": "string",
1431
+ "description": "Secondary address line of the new location."
1432
+ },
1433
+ "pincode": {
1434
+ "type": "number",
1435
+ "description": "Postal code of the new location."
1436
+ },
1437
+ "state": {
1438
+ "type": "string",
1439
+ "description": "State where the new location is situated."
1440
+ },
1441
+ "country": {
1442
+ "type": "string",
1443
+ "description": "State where the new location is situated."
1444
+ },
1445
+ "city": {
1446
+ "type": "string",
1447
+ "description": "City where the new location is situated."
1448
+ },
1449
+ "number": {
1450
+ "type": "string",
1451
+ "description": "Contact number for the new location. 10 digits"
1452
+ },
1453
+ "country_code": {
1454
+ "type": "string",
1455
+ "description": "Country code for the contact number eg 91"
1456
+ },
1457
+ "gst_name": {
1458
+ "type": "string",
1459
+ "description": "GST registered name associated with the new location."
1460
+ },
1461
+ "gst_no": {
1462
+ "type": "string",
1463
+ "description": "GST number associated with the new location."
1464
+ },
1465
+ "latitude": {
1466
+ "type": "number",
1467
+ "description": "Latitude coordinate for the new location."
1468
+ },
1469
+ "longitude": {
1470
+ "type": "number",
1471
+ "description": "Longitude coordinate for the new location."
1472
+ },
1473
+ "manager_name": {
1474
+ "type": "string",
1475
+ "description": "name of the store manager."
1476
+ },
1477
+ "email": {
1478
+ "type": "string",
1479
+ "description": "email of the store manager."
1480
+ }
1481
+ },
1482
+ "required": ["company_id", "address1", "city", "state", 'country', "pincode", "gst_name", "gst_no", 'manager_name', 'email', 'code', 'country_code', 'number']
1483
+ }
1484
+ }, {
1485
+ "name": "updateLocation",
1486
+ "description": "update a existing location for a specified company.",
1487
+ "parameters": {
1488
+ "type": "object",
1489
+ "properties": {
1490
+ "company_id": {
1491
+ "type": "number",
1492
+ "description": "Unique identifier of the company."
1493
+ },
1494
+ "location_id": {
1495
+ "type": "number",
1496
+ "description": "Unique identifier of the location."
1497
+ },
1498
+ "address1": {
1499
+ "type": "string",
1500
+ "description": "Primary address line of the new location."
1501
+ },
1502
+ "address2": {
1503
+ "type": "string",
1504
+ "description": "Secondary address line of the new location."
1505
+ },
1506
+ "pincode": {
1507
+ "type": "string",
1508
+ "description": "Postal code of the new location."
1509
+ },
1510
+ "state": {
1511
+ "type": "string",
1512
+ "description": "State where the new location is situated."
1513
+ },
1514
+ "city": {
1515
+ "type": "string",
1516
+ "description": "City where the new location is situated."
1517
+ },
1518
+ "number": {
1519
+ "type": "string",
1520
+ "description": "Contact number for the new location."
1521
+ },
1522
+ "country_code": {
1523
+ "type": "string",
1524
+ "description": "Country code for the contact number."
1525
+ },
1526
+ "gst_name": {
1527
+ "type": "string",
1528
+ "description": "GST registered name associated with the new location."
1529
+ },
1530
+ "gst_no": {
1531
+ "type": "string",
1532
+ "description": "GST number associated with the new location."
1533
+ },
1534
+ "latitude": {
1535
+ "type": "number",
1536
+ "description": "Latitude coordinate for the new location."
1537
+ },
1538
+ "longitude": {
1539
+ "type": "number",
1540
+ "description": "Longitude coordinate for the new location."
1541
+ }
1542
+ },
1543
+ "required": ["company_id", 'brand_id', "address1", "city", "state", "pincode", "country_code", "gst_name", "gst_no"]
1544
+ }
1545
+ }, {
1546
+ "name": "createProduct",
1547
+ "description": "Creates a new product in the company's catalog.",
1548
+ "parameters": {
1549
+ "type": "object",
1550
+ "properties": {
1551
+ "name": {
1552
+ "type": "string",
1553
+ "description": "Name of the new product."
1554
+ },
1555
+ "company_id": {
1556
+ "type": "number",
1557
+ "description": "Unique identifier of the company."
1558
+ },
1559
+ "slug": {
1560
+ "type": "string",
1561
+ "description": "SEO-friendly URL segment for the product."
1562
+ },
1563
+ "seller_identifier": {
1564
+ "type": "string",
1565
+ "description": "Unique identifier for the seller of the product."
1566
+ },
1567
+ "brand_id": {
1568
+ "type": "number",
1569
+ "description": "Unique identifier of the brand associated with the product."
1570
+ },
1571
+ "mrp": {
1572
+ "type": "number",
1573
+ "description": "Maximum Retail Price of the product."
1574
+ },
1575
+ "selling_price": {
1576
+ "type": "number",
1577
+ "description": "Selling price of the product."
1578
+ }
1579
+ },
1580
+ "required": ["name", "company_id", "slug", "seller_identifier", "brand_id"]
1581
+ }
1582
+ }, {
1583
+ "name": "createInventory",
1584
+ "description": "Creates a new inventory record for a specific product in a company.",
1585
+ "parameters": {
1586
+ "type": "object",
1587
+ "properties": {
1588
+ "company_id": {
1589
+ "type": "number",
1590
+ "description": "Unique identifier of the company."
1591
+ },
1592
+ "product_id": {
1593
+ "type": "number",
1594
+ "description": "Unique identifier of the product."
1595
+ },
1596
+ "seller_identifier": {
1597
+ "type": "string",
1598
+ "description": "Unique identifier for the seller of the product."
1599
+ },
1600
+ "location_id": {
1601
+ "type": "number",
1602
+ "description": "Unique identifier of the location where the inventory is stored."
1603
+ },
1604
+ "mrp": {
1605
+ "type": "number",
1606
+ "description": "Maximum Retail Price of the product."
1607
+ },
1608
+ "selling_price": {
1609
+ "type": "number",
1610
+ "description": "Selling price of the product."
1611
+ }
1612
+ },
1613
+ "required": ["company_id", "product_id", "seller_identifier", "location_id"]
1614
+ }
1615
+ }, {
1616
+ "name": "createApplication",
1617
+ "description": "Creates a new application for a specified company.",
1618
+ "parameters": {
1619
+ "type": "object",
1620
+ "properties": {
1621
+ "company_id": {
1622
+ "type": "number",
1623
+ "description": "Unique identifier of the company."
1624
+ },
1625
+ "brand_ids": {
1626
+ "type": "array",
1627
+ "description": "Array of brand IDs associated with the application.",
1628
+ "items": {
1629
+ "type": "number"
1630
+ }
1631
+ },
1632
+ "name": {
1633
+ "type": "string",
1634
+ "description": "Name of the new application."
1635
+ },
1636
+ "subdomain": {
1637
+ "type": "string",
1638
+ "description": "Subdomain for the application's URL."
1639
+ }
1640
+ },
1641
+ "required": ["company_id", "brand_ids", "name", "subdomain"]
1642
+ }
1643
+ }
1644
+
1645
+ ];
1646
+
1647
+ const messages = [{
1648
+ role: 'system',
1649
+ content: `you are an onboarding buddy chatbot for fynd platform, you help logged in userd who have access to a company to clear their salechannels/ websites, always start by asking the same. when asking questions from the use ask one at a time, ask user for one input at a time. You must initiate the conversation always.
1650
+
1651
+ NOTEs FOR YOU:
1652
+ always check if you have the credentials for a company_id
1653
+ you always show the function name and the generated JSON args when functions are called
1654
+ platform domain is platfrom.fyndx5.de
1655
+ to get started yo need to get the companyId, clientId and secret from the user. always check if the credentials exist, if not save them
1656
+ to create a sales channel you require at least one brand. fetch and show the brands
1657
+ to create a product you need a brand. fetch and show the brand
1658
+ once the product is created it takes some time reflect in the db before the inventory is added
1659
+ for a product to be visible on your sales channel you must also add inventory for it
1660
+ stores, location, warehouses mean the same,
1661
+ seller_identifier, item_code are unique indentifier of the product, both may be the same
1662
+ assume seller_identifier is a string separated by _ and in all caps always.
1663
+ assume data if possible
1664
+
1665
+ UI Links: always give the ui link when performing actions
1666
+ company credentials create link = https://platform.fyndx5.de/company/{companyId}/apis/oauthclient/create
1667
+ company homepage url = https://platform.fyndx5.de/company/{companyId}/home
1668
+ company profile url = https://platform.fyndx5.de/company/{companyId}/profile
1669
+ company location url = https://platform.fyndx5.de/company/{companyId}/profile/edit-store/{locationId}
1670
+ company brand url = https://platform.fyndx5.de/company/{companyId}/profile/edit-brand/{brandId}
1671
+ company sales channels url = https://platform.fyndx5.de/company/{companyId}/application/{applicationId}/products
1672
+ company product listing url= https://platform.fyndx5.de/company/{companyId}/products/list
1673
+ company product url = https://platform.fyndx5.de/company/{companyId}/products/{itemId}/edit.`
1674
+ }];
1675
+ const session = req.jio_copilot_anonymous_session;
1676
+ if (session) {
1677
+ messages.push(...(await listCache.getAll(session)));
1678
+ }
1679
+
1680
+ const userMessage = { role: 'user', content: req.body.prompt };
1681
+ messages.push(userMessage);
1682
+ await listCache.setItems(session, userMessage);
1683
+
1684
+ res.setHeader('Cache-Control', 'no-cache');
1685
+ res.setHeader('Content-Type', 'text/event-stream');
1686
+ // res.setHeader('Access-Control-Allow-Origin', http://);
1687
+ res.setHeader('Connection', 'keep-alive');
1688
+ res.flushHeaders();
1689
+
1690
+ try {
1691
+ await nextStep(session, messages, skills, functions, res);
1692
+ res.end();
1693
+ } catch (error) {
1694
+ if (error.code === 'context_length_exceeded') {
1695
+ res.write('You have exhausted the conversation limit, clear history and start again!');
1696
+ res.end();
1697
+ }
1698
+ res.write('There is some issue is going on. Please try again later.');
1699
+ res.end();
1700
+ }
1701
+ });
1702
+
1703
+ app.use("/api", router);
1704
+ app.use(errorHandler)
1705
+
1706
+ app.listen(port, async () => {
1707
+ console.log(`Example app listening at http://localhost:${port}`);
1708
+ const swaggerSpec = swaggerJSDoc(options);
1709
+
1710
+ // Convert to YAML
1711
+ const swaggerYAML = yaml.dump(swaggerSpec);
1712
+ await fs.writeFileSync("swagger.yaml", swaggerYAML, 'utf-8')
1713
+ await fs.writeFileSync("swagger.json", JSON.stringify(swaggerSpec, null, 2), 'utf-8')
1714
+ });
1715
+
1716
+ async function nextStep(session, messages, skills, functions, res) {
1717
+ const conn = new OpenAI({ apiKey: "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" });
1718
+ const streamResponse = await conn
1719
+ .chat.completions.create({
1720
+ model: 'gpt-4',
1721
+ messages,
1722
+ functions,
1723
+ function_call: 'auto',
1724
+ temperature: 0.5,
1725
+ stream: true
1726
+ }).catch(async err => {
1727
+ console.error(err);
1728
+ const openAIError = new Error(err.error.message);
1729
+ openAIError.code = err.error.code;
1730
+ throw openAIError;
1731
+ });
1732
+
1733
+ let finalMessage = '';
1734
+ const functionCall = { name: null, arguments: '' };
1735
+
1736
+ for await (const line of streamResponse) {
1737
+ const choice = line.choices[0];
1738
+ if (choice.delta.function_call) {
1739
+ const fc = choice.delta.function_call;
1740
+ if (fc.name) {
1741
+ // res.write(`Detected Function: ${fc.name}\n\n`);
1742
+ // res.flush();
1743
+ functionCall.name = fc.name;
1744
+ }
1745
+ if (fc.arguments) {
1746
+ functionCall.arguments += fc.arguments;
1747
+ }
1748
+ } else if (!choice.finish_reason && choice.delta.content) {
1749
+ finalMessage += choice.delta.content;
1750
+ res.write(`${choice.delta.content}`);
1751
+ res.flush();
1752
+ }
1753
+ }
1754
+
1755
+ if (!functionCall.name) {
1756
+ const assistantMessage = { role: 'assistant', content: finalMessage };
1757
+ messages.push(assistantMessage);
1758
+ await listCache.setItems(session, assistantMessage);
1759
+ return;
1760
+ }
1761
+
1762
+ const functionName = functionCall.name;
1763
+ const args = JSON.parse(functionCall.arguments);
1764
+ if (!skills[functionName]) {
1765
+ throw new Error(`No skill implemented for this function: ${functionName}`);
1766
+ }
1767
+
1768
+ // res.write(`Executing Function: ${functionName} with arguments ${JSON.stringify(args)} \n\n`);
1769
+ // res.flush();
1770
+ const skillRes = await skills[functionName]({ ...args, headers: { 'openai-ephemeral-user-id': session } }).catch(e => {
1771
+ return { message: e }
1772
+ });
1773
+
1774
+ if (skillRes) {
1775
+ const functionMessage = { role: 'function', name: functionName, content: JSON.stringify(skillRes) };
1776
+ messages.push(functionMessage);
1777
+ await listCache.setItems(session, functionMessage);
1778
+ }
1779
+ return nextStep(session, messages, skills, functions, res);
1780
+ }
1781
+
1782
+ export const handler = serverless(api);
1783
+
netlify.tolm ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ [functions]
2
+ external_node_modules = ["express"]
3
+ node_bundler = "esbuild"
4
+ [[redirects]]
5
+ force = true
6
+ from = "/api/*"
7
+ status = 200
8
+ to = "/.netlify/functions/api/:splat"
9
+
package.json CHANGED
@@ -10,6 +10,8 @@
10
  },
11
  "dependencies": {
12
  "@gofynd/fdk-client-javascript": "^1.3.10-beta.1",
 
 
13
  "compression": "^1.7.4",
14
  "convict": "^6.2.4",
15
  "cookie-parser": "^1.4.6",
@@ -19,6 +21,7 @@
19
  "js-yaml": "^4.1.0",
20
  "nanoid": "^5.0.4",
21
  "openai": "^4.20.1",
 
22
  "swagger-jsdoc": "^6.2.8"
23
  }
24
  }
 
10
  },
11
  "dependencies": {
12
  "@gofynd/fdk-client-javascript": "^1.3.10-beta.1",
13
+ "@netlify/functions": "^2.4.0",
14
+ "@types/express": "^4.17.21",
15
  "compression": "^1.7.4",
16
  "convict": "^6.2.4",
17
  "cookie-parser": "^1.4.6",
 
21
  "js-yaml": "^4.1.0",
22
  "nanoid": "^5.0.4",
23
  "openai": "^4.20.1",
24
+ "serverless-http": "^3.2.0",
25
  "swagger-jsdoc": "^6.2.8"
26
  }
27
  }
yarn.lock CHANGED
@@ -131,6 +131,27 @@
131
  resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796"
132
  integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  "@nodelib/fs.scandir@2.1.5":
135
  version "2.1.5"
136
  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -169,11 +190,61 @@
169
  resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
170
  integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  "@types/json-schema@^7.0.6":
173
  version "7.0.15"
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"
@@ -196,6 +267,33 @@
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"
@@ -1010,6 +1108,11 @@ is-path-inside@^3.0.3:
1010
  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
1011
  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
1012
 
 
 
 
 
 
1013
  isexe@^2.0.0:
1014
  version "2.0.0"
1015
  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -1432,6 +1535,11 @@ serve-static@1.15.0:
1432
  parseurl "~1.3.3"
1433
  send "0.18.0"
1434
 
 
 
 
 
 
1435
  set-function-length@^1.1.1:
1436
  version "1.1.1"
1437
  resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed"
@@ -1578,6 +1686,11 @@ uri-js@^4.2.2:
1578
  dependencies:
1579
  punycode "^2.1.0"
1580
 
 
 
 
 
 
1581
  utils-merge@1.0.1:
1582
  version "1.0.1"
1583
  resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
 
131
  resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796"
132
  integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==
133
 
134
+ "@netlify/functions@^2.4.0":
135
+ version "2.4.0"
136
+ resolved "https://registry.yarnpkg.com/@netlify/functions/-/functions-2.4.0.tgz#14cc222c44881e7fb3769a458e72a9f1216aff21"
137
+ integrity sha512-dIqhdj5u4Lu/8qbYwtYpn8NfvIyPHbSTV2lAP4ocL+iwC9As06AXT0wa/xOpO2vRWJa0IMxdZaqCPnkyHlHiyg==
138
+ dependencies:
139
+ "@netlify/serverless-functions-api" "1.11.0"
140
+ is-promise "^4.0.0"
141
+
142
+ "@netlify/node-cookies@^0.1.0":
143
+ version "0.1.0"
144
+ resolved "https://registry.yarnpkg.com/@netlify/node-cookies/-/node-cookies-0.1.0.tgz#dda912ba618527695cf519fafa221c5e6777c612"
145
+ integrity sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==
146
+
147
+ "@netlify/serverless-functions-api@1.11.0":
148
+ version "1.11.0"
149
+ resolved "https://registry.yarnpkg.com/@netlify/serverless-functions-api/-/serverless-functions-api-1.11.0.tgz#b6fd1909933e50037e37573cb054706465e03a6e"
150
+ integrity sha512-3splAsr2CekL7VTwgo6yTvzD2+f269/s+TJafYazonqMNNo31yzvFxD5HpLtni4DNE1ppymVKZ4X/rLN3yl0vQ==
151
+ dependencies:
152
+ "@netlify/node-cookies" "^0.1.0"
153
+ urlpattern-polyfill "8.0.2"
154
+
155
  "@nodelib/fs.scandir@2.1.5":
156
  version "2.1.5"
157
  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
 
190
  resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
191
  integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
192
 
193
+ "@types/body-parser@*":
194
+ version "1.19.5"
195
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4"
196
+ integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==
197
+ dependencies:
198
+ "@types/connect" "*"
199
+ "@types/node" "*"
200
+
201
+ "@types/connect@*":
202
+ version "3.4.38"
203
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858"
204
+ integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==
205
+ dependencies:
206
+ "@types/node" "*"
207
+
208
+ "@types/express-serve-static-core@^4.17.33":
209
+ version "4.17.41"
210
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz#5077defa630c2e8d28aa9ffc2c01c157c305bef6"
211
+ integrity sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==
212
+ dependencies:
213
+ "@types/node" "*"
214
+ "@types/qs" "*"
215
+ "@types/range-parser" "*"
216
+ "@types/send" "*"
217
+
218
+ "@types/express@^4.17.21":
219
+ version "4.17.21"
220
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d"
221
+ integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==
222
+ dependencies:
223
+ "@types/body-parser" "*"
224
+ "@types/express-serve-static-core" "^4.17.33"
225
+ "@types/qs" "*"
226
+ "@types/serve-static" "*"
227
+
228
+ "@types/http-errors@*":
229
+ version "2.0.4"
230
+ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
231
+ integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
232
+
233
  "@types/json-schema@^7.0.6":
234
  version "7.0.15"
235
  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
236
  integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
237
 
238
+ "@types/mime@*":
239
+ version "3.0.4"
240
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45"
241
+ integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==
242
+
243
+ "@types/mime@^1":
244
+ version "1.3.5"
245
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
246
+ integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
247
+
248
  "@types/node-fetch@^2.6.4":
249
  version "2.6.9"
250
  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.9.tgz#15f529d247f1ede1824f7e7acdaa192d5f28071e"
 
267
  dependencies:
268
  undici-types "~5.26.4"
269
 
270
+ "@types/qs@*":
271
+ version "6.9.10"
272
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.10.tgz#0af26845b5067e1c9a622658a51f60a3934d51e8"
273
+ integrity sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==
274
+
275
+ "@types/range-parser@*":
276
+ version "1.2.7"
277
+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
278
+ integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
279
+
280
+ "@types/send@*":
281
+ version "0.17.4"
282
+ resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a"
283
+ integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==
284
+ dependencies:
285
+ "@types/mime" "^1"
286
+ "@types/node" "*"
287
+
288
+ "@types/serve-static@*":
289
+ version "1.15.5"
290
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033"
291
+ integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==
292
+ dependencies:
293
+ "@types/http-errors" "*"
294
+ "@types/mime" "*"
295
+ "@types/node" "*"
296
+
297
  "@ungap/structured-clone@^1.2.0":
298
  version "1.2.0"
299
  resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
 
1108
  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
1109
  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
1110
 
1111
+ is-promise@^4.0.0:
1112
+ version "4.0.0"
1113
+ resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3"
1114
+ integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==
1115
+
1116
  isexe@^2.0.0:
1117
  version "2.0.0"
1118
  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
 
1535
  parseurl "~1.3.3"
1536
  send "0.18.0"
1537
 
1538
+ serverless-http@^3.2.0:
1539
+ version "3.2.0"
1540
+ resolved "https://registry.yarnpkg.com/serverless-http/-/serverless-http-3.2.0.tgz#68acc7735f7c876733c04f038ee20f31f5ebfc9b"
1541
+ integrity sha512-QvSyZXljRLIGqwcJ4xsKJXwkZnAVkse1OajepxfjkBXV0BMvRS5R546Z4kCBI8IygDzkQY0foNPC/rnipaE9pQ==
1542
+
1543
  set-function-length@^1.1.1:
1544
  version "1.1.1"
1545
  resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed"
 
1686
  dependencies:
1687
  punycode "^2.1.0"
1688
 
1689
+ urlpattern-polyfill@8.0.2:
1690
+ version "8.0.2"
1691
+ resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz#99f096e35eff8bf4b5a2aa7d58a1523d6ebc7ce5"
1692
+ integrity sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==
1693
+
1694
  utils-merge@1.0.1:
1695
  version "1.0.1"
1696
  resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"