{"version":3,"sources":["../src/reflection.ts"],"sourcesContent":["/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport express from 'express';\nimport fs from 'fs/promises';\nimport getPort, { makeRange } from 'get-port';\nimport { Server } from 'http';\nimport path from 'path';\nimport * as z from 'zod';\nimport {\n  StatusCodes,\n  runWithStreamingCallback,\n  type Status,\n} from './action.js';\nimport { GENKIT_REFLECTION_API_SPEC_VERSION, GENKIT_VERSION } from './index.js';\nimport { logger } from './logging.js';\nimport { Registry } from './registry.js';\nimport { toJsonSchema } from './schema.js';\nimport { flushTracing, setTelemetryServerUrl } from './tracing.js';\n\n// TODO: Move this to common location for schemas.\nexport const RunActionResponseSchema = z.object({\n  result: z.unknown().optional(),\n  error: z.unknown().optional(),\n  telemetry: z\n    .object({\n      traceId: z.string().optional(),\n    })\n    .optional(),\n});\nexport type RunActionResponse = z.infer<typeof RunActionResponseSchema>;\n\nexport interface ReflectionServerOptions {\n  /** Port to run the server on. Actual port may be different if chosen port is occupied. Defaults to 3100. */\n  port?: number;\n  /** Body size limit for the server. Defaults to `30mb`. */\n  bodyLimit?: string;\n  /** Configured environments. Defaults to `dev`. */\n  configuredEnvs?: string[];\n}\n\n/**\n * Reflection server exposes an API for inspecting and interacting with Genkit in development.\n *\n * This is for use in development environments.\n *\n * @hidden\n */\nexport class ReflectionServer {\n  /** List of all running servers needed to be cleaned up on process exit. */\n  private static RUNNING_SERVERS: ReflectionServer[] = [];\n\n  /** Registry instance to be used for API calls. */\n  private registry: Registry;\n  /** Options for the reflection server. */\n  private options: ReflectionServerOptions;\n  /** Port the server is actually running on. This may differ from `options.port` if the original was occupied. Null if server is not running. */\n  private port: number | null = null;\n  /** Express server instance. Null if server is not running. */\n  private server: Server | null = null;\n  /** Path to the runtime file. Null if server is not running. */\n  private runtimeFilePath: string | null = null;\n\n  constructor(registry: Registry, options?: ReflectionServerOptions) {\n    this.registry = registry;\n    this.options = {\n      port: 3100,\n      bodyLimit: '30mb',\n      configuredEnvs: ['dev'],\n      ...options,\n    };\n  }\n\n  /**\n   * Finds a free port to run the server on based on the original chosen port and environment.\n   */\n  async findPort(): Promise<number> {\n    const chosenPort = this.options.port!;\n    const freePort = await getPort({\n      port: makeRange(chosenPort, chosenPort + 100),\n    });\n    if (freePort !== chosenPort) {\n      logger.warn(\n        `Port ${chosenPort} is already in use, using next available port ${freePort} instead.`\n      );\n    }\n    return freePort;\n  }\n\n  /**\n   * Starts the server.\n   *\n   * The server will be registered to be shut down on process exit.\n   */\n  async start() {\n    const server = express();\n\n    server.use(express.json({ limit: this.options.bodyLimit }));\n    server.use(function (req, res, next) {\n      res.header('x-genkit-version', GENKIT_VERSION);\n      next();\n    });\n\n    server.get('/api/__health', async (_, response) => {\n      await this.registry.listActions();\n      response.status(200).send('OK');\n    });\n\n    server.get('/api/__quitquitquit', async (_, response) => {\n      logger.debug('Received quitquitquit');\n      response.status(200).send('OK');\n      await this.stop();\n    });\n\n    server.get('/api/actions', async (_, response, next) => {\n      logger.debug('Fetching actions.');\n      try {\n        const actions = await this.registry.listActions();\n        const convertedActions = {};\n        Object.keys(actions).forEach((key) => {\n          const action = actions[key].__action;\n          convertedActions[key] = {\n            key,\n            name: action.name,\n            description: action.description,\n            metadata: action.metadata,\n          };\n          if (action.inputSchema || action.inputJsonSchema) {\n            convertedActions[key].inputSchema = toJsonSchema({\n              schema: action.inputSchema,\n              jsonSchema: action.inputJsonSchema,\n            });\n          }\n          if (action.outputSchema || action.outputJsonSchema) {\n            convertedActions[key].outputSchema = toJsonSchema({\n              schema: action.outputSchema,\n              jsonSchema: action.outputJsonSchema,\n            });\n          }\n        });\n        response.send(convertedActions);\n      } catch (err) {\n        const { message, stack } = err as Error;\n        next({ message, stack });\n      }\n    });\n\n    server.post('/api/runAction', async (request, response, next) => {\n      const { key, input, context, telemetryLabels } = request.body;\n      const { stream } = request.query;\n      logger.debug(`Running action \\`${key}\\` with stream=${stream}...`);\n      try {\n        const action = await this.registry.lookupAction(key);\n        if (!action) {\n          response.status(404).send(`action ${key} not found`);\n          return;\n        }\n        if (stream === 'true') {\n          try {\n            const callback = (chunk) => {\n              response.write(JSON.stringify(chunk) + '\\n');\n            };\n            const result = await runWithStreamingCallback(\n              this.registry,\n              callback,\n              () => action.run(input, { context, onChunk: callback })\n            );\n            await flushTracing();\n            response.write(\n              JSON.stringify({\n                result: result.result,\n                telemetry: {\n                  traceId: result.telemetry.traceId,\n                },\n              } as RunActionResponse)\n            );\n            response.end();\n          } catch (err) {\n            const { message, stack } = err as Error;\n            // since we're streaming, we must do special error handling here -- the headers are already sent.\n            const errorResponse: Status = {\n              code: StatusCodes.INTERNAL,\n              message,\n              details: {\n                stack,\n              },\n            };\n            if ((err as any).traceId) {\n              errorResponse.details.traceId = (err as any).traceId;\n            }\n            response.write(\n              JSON.stringify({\n                error: errorResponse,\n              } as RunActionResponse)\n            );\n            response.end();\n          }\n        } else {\n          const result = await action.run(input, { context, telemetryLabels });\n          await flushTracing();\n          response.send({\n            result: result.result,\n            telemetry: {\n              traceId: result.telemetry.traceId,\n            },\n          } as RunActionResponse);\n        }\n      } catch (err) {\n        const { message, stack, traceId } = err as any;\n        next({ message, stack, traceId });\n      }\n    });\n\n    server.get('/api/envs', async (_, response) => {\n      response.json(this.options.configuredEnvs);\n    });\n\n    server.post('/api/notify', async (request, response) => {\n      const { telemetryServerUrl, reflectionApiSpecVersion } = request.body;\n      if (!process.env.GENKIT_TELEMETRY_SERVER) {\n        if (typeof telemetryServerUrl === 'string') {\n          setTelemetryServerUrl(telemetryServerUrl);\n          logger.debug(\n            `Connected to telemetry server on ${telemetryServerUrl}`\n          );\n        }\n      }\n      if (reflectionApiSpecVersion !== GENKIT_REFLECTION_API_SPEC_VERSION) {\n        if (\n          !reflectionApiSpecVersion ||\n          reflectionApiSpecVersion < GENKIT_REFLECTION_API_SPEC_VERSION\n        ) {\n          logger.warn(\n            'WARNING: Genkit CLI version may be outdated. Please update `genkit-cli` to the latest version.'\n          );\n        } else {\n          logger.warn(\n            'Genkit CLI is newer than runtime library. Some feature may not be supported. ' +\n              'Consider upgrading your runtime library version (debug info: expected ' +\n              `${GENKIT_REFLECTION_API_SPEC_VERSION}, got ${reflectionApiSpecVersion}).`\n          );\n        }\n      }\n      response.status(200).send('OK');\n    });\n\n    server.use((err, req, res, next) => {\n      logger.error(err.stack);\n      const error = err as Error;\n      const { message, stack } = error;\n      const errorResponse: Status = {\n        code: StatusCodes.INTERNAL,\n        message,\n        details: {\n          stack,\n        },\n      };\n      if (err.traceId) {\n        errorResponse.details.traceId = err.traceId;\n      }\n      res.status(500).json(errorResponse);\n    });\n\n    this.port = await this.findPort();\n    this.server = server.listen(this.port, async () => {\n      logger.debug(\n        `Reflection server (${process.pid}) running on http://localhost:${this.port}`\n      );\n      ReflectionServer.RUNNING_SERVERS.push(this);\n      await this.writeRuntimeFile();\n    });\n  }\n\n  /**\n   * Stops the server and removes it from the list of running servers to clean up on exit.\n   */\n  async stop(): Promise<void> {\n    if (!this.server) {\n      return;\n    }\n    return new Promise<void>(async (resolve, reject) => {\n      await this.cleanupRuntimeFile();\n      this.server!.close(async (err) => {\n        if (err) {\n          logger.error(\n            `Error shutting down reflection server on port ${this.port}: ${err}`\n          );\n          reject(err);\n        }\n        const index = ReflectionServer.RUNNING_SERVERS.indexOf(this);\n        if (index > -1) {\n          ReflectionServer.RUNNING_SERVERS.splice(index, 1);\n        }\n        logger.debug(\n          `Reflection server on port ${this.port} has successfully shut down.`\n        );\n        this.port = null;\n        this.server = null;\n        resolve();\n      });\n    });\n  }\n\n  /**\n   * Writes the runtime file to the project root.\n   */\n  private async writeRuntimeFile() {\n    try {\n      const rootDir = await findProjectRoot();\n      const runtimesDir = path.join(rootDir, '.genkit', 'runtimes');\n      const date = new Date();\n      const time = date.getTime();\n      const timestamp = date.toISOString();\n      this.runtimeFilePath = path.join(\n        runtimesDir,\n        `${process.pid}-${time}.json`\n      );\n      const fileContent = JSON.stringify(\n        {\n          id: process.env.GENKIT_RUNTIME_ID || process.pid.toString(),\n          pid: process.pid,\n          reflectionServerUrl: `http://localhost:${this.port}`,\n          timestamp,\n          genkitVersion: `nodejs/${GENKIT_VERSION}`,\n          reflectionApiSpecVersion: GENKIT_REFLECTION_API_SPEC_VERSION,\n        },\n        null,\n        2\n      );\n      await fs.mkdir(runtimesDir, { recursive: true });\n      await fs.writeFile(this.runtimeFilePath, fileContent, 'utf8');\n      logger.debug(`Runtime file written: ${this.runtimeFilePath}`);\n    } catch (error) {\n      logger.error(`Error writing runtime file: ${error}`);\n    }\n  }\n\n  /**\n   * Cleans up the port file.\n   */\n  private async cleanupRuntimeFile() {\n    if (!this.runtimeFilePath) {\n      return;\n    }\n    try {\n      const fileContent = await fs.readFile(this.runtimeFilePath, 'utf8');\n      const data = JSON.parse(fileContent);\n      if (data.pid === process.pid) {\n        await fs.unlink(this.runtimeFilePath);\n        logger.debug(`Runtime file cleaned up: ${this.runtimeFilePath}`);\n      }\n    } catch (error) {\n      logger.error(`Error cleaning up runtime file: ${error}`);\n    }\n  }\n\n  /**\n   * Stops all running reflection servers.\n   */\n  static async stopAll() {\n    return Promise.all(\n      ReflectionServer.RUNNING_SERVERS.map((server) => server.stop())\n    );\n  }\n}\n\n/**\n * Finds the project root by looking for a `package.json` file.\n */\nasync function findProjectRoot(): Promise<string> {\n  let currentDir = process.cwd();\n  while (currentDir !== path.parse(currentDir).root) {\n    const packageJsonPath = path.join(currentDir, 'package.json');\n    try {\n      await fs.access(packageJsonPath);\n      return currentDir;\n    } catch {\n      currentDir = path.dirname(currentDir);\n    }\n  }\n  throw new Error('Could not find project root (package.json not found)');\n}\n\n// TODO: Verify that this works.\nif (typeof module !== 'undefined' && 'hot' in module) {\n  (module as any).hot.accept();\n  (module as any).hot.dispose(async () => {\n    logger.debug('Cleaning up reflection server(s) before module reload...');\n    await ReflectionServer.stopAll();\n  });\n}\n"],"mappings":"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","names":[]}