{"version":3,"sources":["../../src/client/client.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 { Channel, createTask } from '@genkit-ai/core/async';\n\nconst __flowStreamDelimiter = '\\n\\n';\n\n/**\n * Invoke and stream response from a deployed flow.\n *\n * For example:\n *\n * ```js\n * import { streamFlow } from 'genkit/beta/client';\n *\n * const response = streamFlow({\n *   url: 'https://my-flow-deployed-url',\n *   input: 'foo',\n * });\n * for await (const chunk of response.stream) {\n *   console.log(chunk);\n * }\n * console.log(await response.output);\n * ```\n */\nexport function streamFlow<O = any, S = any>({\n  url,\n  input,\n  streamId,\n  headers,\n  abortSignal,\n}: {\n  /** URL of the deployed flow. */\n  url: string;\n  /** Flow input. */\n  input?: any;\n  /** Stream ID to connect to. */\n  streamId?: string;\n  /** A map of HTTP headers to be added to the HTTP call. */\n  headers?: Record<string, string>;\n  /** Abort signal to abort the request. */\n  abortSignal?: AbortSignal;\n}): {\n  readonly output: Promise<O>;\n  readonly stream: AsyncIterable<S>;\n  readonly streamId: Promise<string | null>;\n} {\n  const channel = new Channel<S>();\n  const streamIdTask = createTask<string | null>();\n\n  const operationPromise = __flowRunEnvelope({\n    url,\n    input,\n    sendChunk: (c) => channel.send(c),\n    headers: streamId\n      ? { ...headers, 'x-genkit-stream-id': streamId }\n      : headers,\n    abortSignal,\n    responseCallback: (response) => {\n      streamIdTask.resolve(response.headers.get('x-genkit-stream-id'));\n    },\n  });\n  operationPromise.then(\n    () => channel.close(),\n    (err) => channel.error(err)\n  );\n\n  return {\n    output: operationPromise,\n    stream: channel,\n    streamId: streamIdTask.promise,\n  };\n}\n\nasync function __flowRunEnvelope({\n  url,\n  input,\n  sendChunk,\n  headers,\n  abortSignal,\n  responseCallback,\n}: {\n  url: string;\n  input: any;\n  sendChunk: (chunk: any) => void;\n  headers?: Record<string, string>;\n  abortSignal?: AbortSignal;\n  responseCallback?: (response: Response) => void;\n}) {\n  const response = await fetch(url, {\n    method: 'POST',\n    body: JSON.stringify({\n      data: input,\n    }),\n    headers: {\n      Accept: 'text/event-stream',\n      'Content-Type': 'application/json',\n      ...headers,\n    },\n    signal: abortSignal,\n  });\n  if (responseCallback) {\n    responseCallback(response);\n  }\n  if (response.status === 204) {\n    throw new Error('NOT_FOUND: Stream not found.');\n  }\n  if (response.status !== 200) {\n    throw new Error(\n      `Server returned: ${response.status}: ${await response.text()}`\n    );\n  }\n  if (!response.body) {\n    throw new Error('Response body is empty');\n  }\n  var reader = response.body.getReader();\n  var decoder = new TextDecoder();\n\n  let buffer = '';\n  while (true) {\n    const result = await reader.read();\n    const decodedValue = decoder.decode(result.value);\n    if (decodedValue) {\n      buffer += decodedValue;\n    }\n    // If buffer includes the delimiter that means we are still receiving chunks.\n    while (buffer.includes(__flowStreamDelimiter)) {\n      const chunk = JSON.parse(\n        buffer\n          .substring(0, buffer.indexOf(__flowStreamDelimiter))\n          .substring('data: '.length)\n      );\n      if (chunk.hasOwnProperty('message')) {\n        sendChunk(chunk.message);\n      } else if (chunk.hasOwnProperty('result')) {\n        return chunk.result;\n      } else if (chunk.hasOwnProperty('error')) {\n        throw new Error(\n          `${chunk.error.status}: ${chunk.error.message}\\n${chunk.error.details}`\n        );\n      } else {\n        throw new Error('unknown chunk format: ' + JSON.stringify(chunk));\n      }\n      buffer = buffer.substring(\n        buffer.indexOf(__flowStreamDelimiter) + __flowStreamDelimiter.length\n      );\n    }\n  }\n  throw new Error('stream did not terminate correctly');\n}\n\n/**\n * Invoke a deployed flow over HTTP(s).\n *\n * For example:\n *\n * ```js\n * import { runFlow } from 'genkit/beta/client';\n *\n * const response = await runFlow({\n *   url: 'https://my-flow-deployed-url',\n *   input: 'foo',\n * });\n * console.log(await response);\n * ```\n */\nexport async function runFlow<O = any>({\n  url,\n  input,\n  headers,\n  abortSignal,\n}: {\n  /** URL of the deployed flow. */\n  url: string;\n  /** Flow input. */\n  input?: any;\n  /** A map of HTTP headers to be added to the HTTP call. */\n  headers?: Record<string, string>;\n  /** Abort signal to abort the request. */\n  abortSignal?: AbortSignal;\n}): Promise<O> {\n  const response = await fetch(url, {\n    method: 'POST',\n    body: JSON.stringify({\n      data: input,\n    }),\n    headers: {\n      'Content-Type': 'application/json',\n      ...headers,\n    },\n    signal: abortSignal,\n  });\n  if (response.status !== 200) {\n    throw new Error(\n      `Server returned: ${response.status}: ${await response.text()}`\n    );\n  }\n  const wrappedResult = (await response.json()) as\n    | { result: O }\n    | { error: unknown };\n  if ('error' in wrappedResult) {\n    if (typeof wrappedResult.error === 'string') {\n      throw new Error(wrappedResult.error);\n    }\n    // TODO: The callable protocol defines an HttpError that has a JSON format of\n    // details?: string\n    // httpErrorCode: { canonicalName: string }\n    // message: string\n    // Should we create a new error class that parses this and exposes it as fields?\n    throw new Error(JSON.stringify(wrappedResult.error));\n  }\n  return wrappedResult.result;\n}\n"],"mappings":"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","names":[]}