fexapi 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +115 -1
  2. package/dist/cli/args.d.ts +15 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +53 -0
  5. package/dist/cli/help.d.ts +2 -0
  6. package/dist/cli/help.d.ts.map +1 -0
  7. package/dist/cli/help.js +40 -0
  8. package/dist/commands/generate.d.ts +2 -0
  9. package/dist/commands/generate.d.ts.map +1 -0
  10. package/dist/commands/generate.js +73 -0
  11. package/dist/commands/init.d.ts +4 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/init.js +66 -0
  14. package/dist/commands/serve.d.ts +5 -0
  15. package/dist/commands/serve.d.ts.map +1 -0
  16. package/dist/commands/serve.js +56 -0
  17. package/dist/config/generated-spec.d.ts +3 -0
  18. package/dist/config/generated-spec.d.ts.map +1 -0
  19. package/dist/config/generated-spec.js +26 -0
  20. package/dist/config/runtime-config.d.ts +3 -0
  21. package/dist/config/runtime-config.d.ts.map +1 -0
  22. package/dist/config/runtime-config.js +97 -0
  23. package/dist/config/schema-definitions.d.ts +3 -0
  24. package/dist/config/schema-definitions.d.ts.map +1 -0
  25. package/dist/config/schema-definitions.js +90 -0
  26. package/dist/constants.d.ts +2 -0
  27. package/dist/constants.d.ts.map +1 -0
  28. package/dist/constants.js +4 -0
  29. package/dist/index.js +23 -386
  30. package/dist/project/detect.d.ts +4 -0
  31. package/dist/project/detect.d.ts.map +1 -0
  32. package/dist/project/detect.js +113 -0
  33. package/dist/project/paths.d.ts +3 -0
  34. package/dist/project/paths.d.ts.map +1 -0
  35. package/dist/project/paths.js +28 -0
  36. package/dist/server.d.ts +4 -1
  37. package/dist/server.d.ts.map +1 -1
  38. package/dist/server.js +119 -40
  39. package/dist/types/config.d.ts +20 -0
  40. package/dist/types/config.d.ts.map +1 -0
  41. package/dist/types/config.js +2 -0
  42. package/dist/types/project.d.ts +7 -0
  43. package/dist/types/project.d.ts.map +1 -0
  44. package/dist/types/project.js +2 -0
  45. package/package.json +53 -51
@@ -0,0 +1,3 @@
1
+ export declare const findClosestPackageJson: (startDirectory: string) => string | undefined;
2
+ export declare const resolveProjectRoot: () => string | undefined;
3
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/project/paths.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB,GACjC,gBAAgB,MAAM,KACrB,MAAM,GAAG,SAgBX,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAO,MAAM,GAAG,SAO9C,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveProjectRoot = exports.findClosestPackageJson = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const findClosestPackageJson = (startDirectory) => {
7
+ let currentDirectory = startDirectory;
8
+ while (true) {
9
+ const candidate = (0, node_path_1.join)(currentDirectory, "package.json");
10
+ if ((0, node_fs_1.existsSync)(candidate)) {
11
+ return candidate;
12
+ }
13
+ const parentDirectory = (0, node_path_1.dirname)(currentDirectory);
14
+ if (parentDirectory === currentDirectory) {
15
+ return undefined;
16
+ }
17
+ currentDirectory = parentDirectory;
18
+ }
19
+ };
20
+ exports.findClosestPackageJson = findClosestPackageJson;
21
+ const resolveProjectRoot = () => {
22
+ const packageJsonPath = (0, exports.findClosestPackageJson)(process.cwd());
23
+ if (!packageJsonPath) {
24
+ return undefined;
25
+ }
26
+ return (0, node_path_1.dirname)(packageJsonPath);
27
+ };
28
+ exports.resolveProjectRoot = resolveProjectRoot;
package/dist/server.d.ts CHANGED
@@ -1,13 +1,16 @@
1
1
  import type { ServerResponse } from "node:http";
2
2
  import type { FexapiRoute } from "./schema";
3
+ import type { FexapiRuntimeConfig, FexapiSchemaDefinitions } from "./types/config";
3
4
  export type ServerOptions = {
4
5
  host?: string;
5
6
  port?: number;
6
7
  apiSpec?: GeneratedApiSpec;
8
+ runtimeConfig?: FexapiRuntimeConfig;
9
+ schemaDefinitions?: FexapiSchemaDefinitions;
7
10
  };
8
11
  export type GeneratedApiSpec = {
9
12
  port: number;
10
13
  routes: FexapiRoute[];
11
14
  };
12
- export declare const startServer: ({ host, port, apiSpec, }?: ServerOptions) => import("http").Server<typeof import("http").IncomingMessage, typeof ServerResponse>;
15
+ export declare const startServer: ({ host, port, apiSpec, runtimeConfig, schemaDefinitions, }?: ServerOptions) => import("http").Server<typeof import("http").IncomingMessage, typeof ServerResponse>;
13
16
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,CAAC;AA2FF,eAAO,MAAM,WAAW,GAAI,2BAIzB,aAAkB,wFA8DpB,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EAExB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,iBAAiB,CAAC,EAAE,uBAAuB,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,CAAC;AAyLF,eAAO,MAAM,WAAW,GAAI,6DAMzB,aAAkB,wFAqGpB,CAAC"}
package/dist/server.js CHANGED
@@ -5,9 +5,25 @@ const faker_1 = require("@faker-js/faker");
5
5
  const node_http_1 = require("node:http");
6
6
  const DEFAULT_HOST = "127.0.0.1";
7
7
  const DEFAULT_PORT = 4000;
8
- const sendJson = (response, statusCode, payload) => {
9
- response.writeHead(statusCode, { "Content-Type": "application/json" });
10
- response.end(JSON.stringify(payload));
8
+ const sendJson = (response, statusCode, payload, options) => {
9
+ const send = () => {
10
+ const headers = {
11
+ "Content-Type": "application/json",
12
+ };
13
+ if (options.cors) {
14
+ headers["Access-Control-Allow-Origin"] = "*";
15
+ headers["Access-Control-Allow-Methods"] =
16
+ "GET,POST,PUT,PATCH,DELETE,OPTIONS";
17
+ headers["Access-Control-Allow-Headers"] = "Content-Type,Authorization";
18
+ }
19
+ response.writeHead(statusCode, headers);
20
+ response.end(JSON.stringify(payload));
21
+ };
22
+ if (options.delay > 0) {
23
+ setTimeout(send, options.delay);
24
+ return;
25
+ }
26
+ send();
11
27
  };
12
28
  const createValueFromField = (field) => {
13
29
  switch (field.type) {
@@ -39,6 +55,62 @@ const createRecordFromRoute = (route) => {
39
55
  return record;
40
56
  }, {});
41
57
  };
58
+ const resolveFakerMethod = (path) => {
59
+ const pathParts = path.split(".").filter(Boolean);
60
+ let current = faker_1.faker;
61
+ for (const pathPart of pathParts) {
62
+ if (typeof current !== "object" || current === null) {
63
+ return undefined;
64
+ }
65
+ current = current[pathPart];
66
+ }
67
+ if (typeof current !== "function") {
68
+ return undefined;
69
+ }
70
+ return current;
71
+ };
72
+ const createValueFromSchemaFieldDefinition = (fieldDefinition) => {
73
+ if (fieldDefinition.faker) {
74
+ const fakerMethod = resolveFakerMethod(fieldDefinition.faker);
75
+ if (fakerMethod) {
76
+ return fakerMethod();
77
+ }
78
+ }
79
+ switch (fieldDefinition.type) {
80
+ case "number": {
81
+ const min = typeof fieldDefinition.min === "number" ? fieldDefinition.min : 1;
82
+ const max = typeof fieldDefinition.max === "number" ? fieldDefinition.max : 10000;
83
+ return faker_1.faker.number.int({
84
+ min: Math.min(min, max),
85
+ max: Math.max(min, max),
86
+ });
87
+ }
88
+ case "boolean":
89
+ return faker_1.faker.datatype.boolean();
90
+ case "date":
91
+ return faker_1.faker.date.recent({ days: 30 }).toISOString();
92
+ case "uuid":
93
+ return faker_1.faker.string.uuid();
94
+ case "email":
95
+ return faker_1.faker.internet.email();
96
+ case "url":
97
+ return faker_1.faker.internet.url();
98
+ case "name":
99
+ return faker_1.faker.person.fullName();
100
+ case "phone":
101
+ return faker_1.faker.phone.number();
102
+ case "string":
103
+ default:
104
+ return faker_1.faker.lorem.words({ min: 1, max: 4 });
105
+ }
106
+ };
107
+ const createRecordFromSchemaDefinition = (schemaDefinition) => {
108
+ const result = {};
109
+ for (const [fieldName, fieldDefinition] of Object.entries(schemaDefinition)) {
110
+ result[fieldName] = createValueFromSchemaFieldDefinition(fieldDefinition);
111
+ }
112
+ return result;
113
+ };
42
114
  const toCollectionKey = (routePath) => {
43
115
  const segments = routePath.split("/").filter(Boolean);
44
116
  const lastSegment = segments[segments.length - 1];
@@ -47,21 +119,17 @@ const toCollectionKey = (routePath) => {
47
119
  }
48
120
  return lastSegment.replace(/[^a-zA-Z0-9_]/g, "_");
49
121
  };
50
- const createMockUser = () => {
51
- return {
52
- id: faker_1.faker.string.uuid(),
53
- fullName: faker_1.faker.person.fullName(),
54
- username: faker_1.faker.internet.username(),
55
- email: faker_1.faker.internet.email(),
56
- avatarUrl: faker_1.faker.image.avatar(),
57
- };
58
- };
59
- const createMockPost = () => {
122
+ const createRecordFromSchemaName = (schemaName, schemaDefinitions) => {
123
+ const normalizedSchemaName = schemaName.trim().toLowerCase();
124
+ const customSchemaDefinition = schemaDefinitions[normalizedSchemaName];
125
+ if (customSchemaDefinition) {
126
+ return createRecordFromSchemaDefinition(customSchemaDefinition);
127
+ }
60
128
  return {
61
129
  id: faker_1.faker.string.uuid(),
62
- title: faker_1.faker.lorem.sentence(),
63
- body: faker_1.faker.lorem.paragraphs({ min: 1, max: 3 }),
64
- createdAt: faker_1.faker.date.recent({ days: 14 }).toISOString(),
130
+ type: normalizedSchemaName || "record",
131
+ value: faker_1.faker.lorem.words({ min: 1, max: 4 }),
132
+ createdAt: faker_1.faker.date.recent({ days: 7 }).toISOString(),
65
133
  };
66
134
  };
67
135
  const getCountFromUrl = (urlText, fallback = 5) => {
@@ -75,16 +143,46 @@ const getCountFromUrl = (urlText, fallback = 5) => {
75
143
  }
76
144
  return Math.min(Math.max(Math.floor(rawCount), 1), 50);
77
145
  };
78
- const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, } = {}) => {
146
+ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtimeConfig, schemaDefinitions = {}, } = {}) => {
147
+ const corsEnabled = runtimeConfig?.cors ?? false;
148
+ const responseDelay = runtimeConfig?.delay ?? 0;
149
+ const configuredRoutes = runtimeConfig?.routes ?? {};
150
+ const availableConfiguredRoutes = Object.keys(configuredRoutes).map((path) => `GET ${path}`);
151
+ const availableSchemaRoutes = apiSpec
152
+ ? apiSpec.routes.map((route) => `${route.method} ${route.path}`)
153
+ : [];
154
+ const availableRoutes = [
155
+ "GET /health",
156
+ ...new Set([...availableConfiguredRoutes, ...availableSchemaRoutes]),
157
+ ];
79
158
  const server = (0, node_http_1.createServer)((request, response) => {
80
159
  const pathname = new URL(request.url ?? "/", "http://localhost").pathname;
160
+ if (corsEnabled && request.method === "OPTIONS") {
161
+ response.writeHead(204, {
162
+ "Access-Control-Allow-Origin": "*",
163
+ "Access-Control-Allow-Methods": "GET,POST,PUT,PATCH,DELETE,OPTIONS",
164
+ "Access-Control-Allow-Headers": "Content-Type,Authorization",
165
+ });
166
+ response.end();
167
+ return;
168
+ }
81
169
  if (request.method === "GET" && pathname === "/health") {
82
170
  sendJson(response, 200, {
83
171
  ok: true,
84
172
  timestamp: new Date().toISOString(),
85
- });
173
+ }, { cors: corsEnabled, delay: responseDelay });
86
174
  return;
87
175
  }
176
+ if (request.method === "GET") {
177
+ const configuredRoute = configuredRoutes[pathname];
178
+ if (configuredRoute) {
179
+ const payloadKey = toCollectionKey(pathname);
180
+ sendJson(response, 200, {
181
+ [payloadKey]: Array.from({ length: configuredRoute.count }, () => createRecordFromSchemaName(configuredRoute.schema, schemaDefinitions)),
182
+ }, { cors: corsEnabled, delay: responseDelay });
183
+ return;
184
+ }
185
+ }
88
186
  if (apiSpec) {
89
187
  const matchedRoute = apiSpec.routes.find((route) => route.method === request.method && route.path === pathname);
90
188
  if (matchedRoute) {
@@ -92,33 +190,14 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, } = {}
92
190
  const payloadKey = toCollectionKey(matchedRoute.path);
93
191
  sendJson(response, 200, {
94
192
  [payloadKey]: Array.from({ length: count }, () => createRecordFromRoute(matchedRoute)),
95
- });
193
+ }, { cors: corsEnabled, delay: responseDelay });
96
194
  return;
97
195
  }
98
196
  }
99
- if (request.method === "GET" && pathname === "/users") {
100
- const count = getCountFromUrl(request.url, 8);
101
- sendJson(response, 200, {
102
- users: Array.from({ length: count }, createMockUser),
103
- });
104
- return;
105
- }
106
- if (request.method === "GET" && pathname === "/posts") {
107
- const count = getCountFromUrl(request.url, 5);
108
- sendJson(response, 200, {
109
- posts: Array.from({ length: count }, createMockPost),
110
- });
111
- return;
112
- }
113
197
  sendJson(response, 404, {
114
198
  message: "Route not found",
115
- availableRoutes: apiSpec
116
- ? [
117
- "GET /health",
118
- ...apiSpec.routes.map((route) => `${route.method} ${route.path}`),
119
- ]
120
- : ["GET /health", "GET /users?count=10", "GET /posts?count=5"],
121
- });
199
+ availableRoutes,
200
+ }, { cors: corsEnabled, delay: responseDelay });
122
201
  });
123
202
  server.listen(port, host, () => {
124
203
  console.log(`Mock API running at http://${host}:${port}`);
@@ -0,0 +1,20 @@
1
+ export type FexapiRouteConfig = {
2
+ count: number;
3
+ schema: string;
4
+ };
5
+ export type FexapiFieldValueType = "number" | "string" | "boolean" | "date" | "uuid" | "email" | "url" | "name" | "phone";
6
+ export type FexapiSchemaFieldDefinition = {
7
+ type: FexapiFieldValueType;
8
+ faker?: string;
9
+ min?: number;
10
+ max?: number;
11
+ };
12
+ export type FexapiSchemaDefinition = Record<string, FexapiSchemaFieldDefinition>;
13
+ export type FexapiSchemaDefinitions = Record<string, FexapiSchemaDefinition>;
14
+ export type FexapiRuntimeConfig = {
15
+ port?: number;
16
+ routes?: Record<string, FexapiRouteConfig>;
17
+ cors?: boolean;
18
+ delay?: number;
19
+ };
20
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,MAAM,GACN,MAAM,GACN,OAAO,GACP,KAAK,GACL,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,MAAM,CACzC,MAAM,EACN,2BAA2B,CAC5B,CAAC;AACF,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;AAE7E,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ export type SupportedFramework = "nextjs" | "reactjs" | "vue" | "nuxt" | "svelte" | "sveltekit" | "angular" | "solid" | "remix" | "astro" | "unknown";
2
+ export type DetectedProject = {
3
+ primaryFramework: SupportedFramework;
4
+ frameworks: SupportedFramework[];
5
+ tooling: string[];
6
+ };
7
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/types/project.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,SAAS,GACT,KAAK,GACL,MAAM,GACN,QAAQ,GACR,WAAW,GACX,SAAS,GACT,OAAO,GACP,OAAO,GACP,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,MAAM,eAAe,GAAG;IAC5B,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,51 +1,53 @@
1
- {
2
- "name": "fexapi",
3
- "version": "0.1.0",
4
- "description": "Mock API generation CLI tool for local development and testing",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
7
- "bin": {
8
- "fexapi": "dist/index.js"
9
- },
10
- "files": [
11
- "dist",
12
- "README.md"
13
- ],
14
- "scripts": {
15
- "build": "tsc -p tsconfig.json",
16
- "check-types": "tsc --noEmit",
17
- "start": "node dist/index.js",
18
- "dev": "tsc -w -p tsconfig.json",
19
- "prepublishOnly": "pnpm build"
20
- },
21
- "keywords": [
22
- "mock",
23
- "api",
24
- "cli",
25
- "testing",
26
- "development",
27
- "faker",
28
- "mock-server"
29
- ],
30
- "author": "Shreeteja Mutukundu smutukundu2006@gmail.com",
31
- "license": "MIT",
32
- "repository": {
33
- "type": "git",
34
- "url": "git+https://github.com/shreeteja172/fexapi.git",
35
- "directory": "apps/cli"
36
- },
37
- "bugs": {
38
- "url": "https://github.com/shreeteja172/fexapi/issues"
39
- },
40
- "homepage": "https://github.com/shreeteja172/fexapi#readme",
41
- "devDependencies": {
42
- "@types/node": "^22.15.3",
43
- "typescript": "5.9.2"
44
- },
45
- "dependencies": {
46
- "@faker-js/faker": "^10.3.0"
47
- },
48
- "engines": {
49
- "node": ">=18.0.0"
50
- }
51
- }
1
+ {
2
+ "name": "fexapi",
3
+ "version": "0.1.1",
4
+ "description": "Mock API generation CLI tool for local development and testing",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "bin": {
8
+ "fexapi": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "check-types": "tsc --noEmit",
17
+ "start": "node dist/index.js",
18
+ "serve": "node dist/index.js serve",
19
+ "dev": "tsc -w -p tsconfig.json",
20
+ "prepublishOnly": "pnpm build"
21
+ },
22
+ "keywords": [
23
+ "mock",
24
+ "api",
25
+ "cli",
26
+ "testing",
27
+ "development",
28
+ "faker",
29
+ "mock-server"
30
+ ],
31
+ "author": "Shreeteja Mutukundu smutukundu2006@gmail.com",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/shreeteja172/fexapi.git",
36
+ "directory": "apps/cli"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/shreeteja172/fexapi/issues"
40
+ },
41
+ "homepage": "https://github.com/shreeteja172/fexapi#readme",
42
+ "devDependencies": {
43
+ "@types/node": "^22.15.3",
44
+ "typescript": "5.9.2"
45
+ },
46
+ "dependencies": {
47
+ "@faker-js/faker": "^10.3.0",
48
+ "yaml": "^2.8.3"
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ }
53
+ }