{"version":3,"sources":["jsdelivr-header.js","/npm/@langchain/langgraph-checkpoint-postgres@1.0.1/src/index.ts"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,iOCuBA,MAAM,gBAAwC,CAC5C,OAAQ,UAGJ,uBACJ,IAEO,IACF,EACH,OAAQ,GAAS,QAAU,gBAAgB,UAIzC,KAAE,MAAS,GAyCjB,IAAa,cAAb,MAAa,UAAsB,oBACjC,KAEA,QAEA,eAEA,QAEA,WAAA,CACE,EACA,EACA,GAEA,MAAM,GACN,KAAK,KAAO,EACZ,KAAK,SAAU,EACf,KAAK,QAAU,uBAAuB,GACtC,KAAK,eAAiB,iBAAiB,KAAK,QAAQ,O,CAiBtD,qBAAO,CACL,EACA,GAGA,OAAO,IAAI,EADE,IAAI,KAAK,CAAE,iBAAkB,SACX,EAAW,E,CAU5C,WAAM,GACJ,MAAM,QAAe,KAAK,KAAK,UACzB,EAAgB,oBAAoB,KAAK,QAAQ,QACvD,UACQ,EAAO,MACX,gCAAgC,KAAK,QAAQ,WAE/C,IAAI,GAAU,EACd,MAAM,EAAa,cAAc,KAAK,QAAQ,QAE9C,IACE,MAAM,QAAe,EAAO,MAC1B,iBAAiB,EAAc,iDAE7B,EAAO,KAAK,OAAS,IACvB,EAAU,EAAO,KAAK,GAAG,E,OAEpB,GAEP,GACmB,iBAAV,GACG,OAAV,KACA,SAAU,IACY,iBAAf,EAAM,MACE,UAAf,EAAM,KAIN,MAAM,EAFN,GAAU,C,CAMd,IAAK,IAAI,EAAI,EAAU,EAAG,EAAI,EAAW,OAAQ,GAAK,QAC9C,EAAO,MAAM,EAAW,UACxB,EAAO,MACX,eAAe,EAAc,wCAC7B,CAAC,G,SAIL,EAAO,S,EAIX,qBAAgB,CACd,EACA,GAEA,MAAO,IACF,EACH,qBAAsB,KAAK,WAAW,G,CAI1C,gBAAgB,CACd,GAEA,IAAK,GAAoC,IAAtB,EAAW,OAC5B,MAAO,GAET,MAAM,EAAc,IAAI,YAClB,QAAgB,QAAQ,IAC5B,EACG,QAAA,EAAQ,CAAG,KAAiC,UAA1B,EAAY,OAAO,KACrC,KAAI,OAAQ,EAAG,EAAG,KAAO,CACxB,EAAY,OAAO,SACb,KAAK,MAAM,WAAW,EAAY,OAAO,GAAI,OAGzD,OAAO,OAAO,YAAY,E,CAG5B,mBAAgB,CAAc,GAC5B,MAAO,EAAM,SAAqB,KAAK,MAAM,WAAW,GACxD,OAAO,KAAK,MAAM,WAAW,EAAM,E,CAGrC,iBAAgB,CACd,GAEA,MAAM,EAAU,IAAI,YACpB,OAAO,QACG,QAAQ,IACZ,EAAO,KAAI,OAAQ,EAAK,EAAS,EAAG,KAAO,CACzC,EAAQ,OAAO,GACf,EAAQ,OAAO,SACT,KAAK,MAAM,WAAW,EAAQ,OAAO,GAAI,OAGnD,E,CAGN,gBAAgB,CACd,EACA,EACA,EACA,GAIA,OAAqC,IAAjC,OAAO,KAAK,GAAU,OACjB,GAGF,QAAQ,IACb,OAAO,QAAQ,GAAU,KAAI,OAAQ,EAAG,MACtC,MAAO,EAAM,GACX,KAAK,QACK,KAAK,MAAM,WAAW,EAAO,IACnC,CAAC,QAAS,MAChB,MAAO,CACL,EACA,EACA,EACA,EAAI,WACJ,EACA,EAAQ,IAAI,WAAW,QAAS,EACjC,I,CAKP,eAAA,CAA0B,GACxB,MAAM,EAAsC,IAAK,GAEjD,MADI,mBAAoB,UAAmB,EAAW,eAC/C,C,CAGT,mBAAgB,CAAc,GAC5B,MAAM,CAAG,SAA4B,KAAK,MAAM,WAAW,GAE3D,OAAO,KAAK,OACV,IAAI,aAAc,OAAO,GAAoB,QAAQ,MAAO,I,CAIhE,iBAAgB,CACd,EACA,EACA,EACA,EACA,GAIA,OAAO,QAAQ,IACb,EAAO,KAAI,OAAQ,EAAS,GAAQ,KAClC,MAAO,EAAM,SAAyB,KAAK,MAAM,WAAW,GAC5D,MAAO,CACL,EACA,EACA,EACA,EACA,eAAe,IAAY,EAC3B,EACA,EACA,IAAI,WAAW,GAChB,I,CAaP,YAAA,CACE,EACA,EACA,GAEA,MAAM,EAAmB,GACnB,EAAyB,GAkC/B,OA/BI,GAAQ,cAAc,YACxB,EAAO,KAAK,gBAAgB,EAAY,OAAS,KACjD,EAAY,KAAK,EAAO,aAAa,YAKrC,SAAQ,cAAc,gBAGtB,EAAO,KAAK,oBAAoB,EAAY,OAAS,KACrD,EAAY,KAAK,EAAO,aAAa,gBAGnC,GAAQ,cAAc,gBACxB,EAAO,KAAK,oBAAoB,EAAY,OAAS,KACrD,EAAY,KAAK,EAAO,aAAa,gBAInC,GAAU,OAAO,KAAK,GAAQ,OAAS,IACzC,EAAO,KAAK,gBAAgB,EAAY,OAAS,KACjD,EAAY,KAAK,KAAK,UAAU,UAIU,IAAxC,GAAQ,cAAc,gBACxB,EAAO,KAAK,oBAAoB,EAAY,OAAS,KACrD,EAAY,KAAK,EAAO,aAAa,gBAGhC,CACL,EAAO,OAAS,EAAI,SAAS,EAAO,KAAK,WAAa,GACtD,E,CAcJ,cAAM,CAAS,GACb,MAAM,UACJ,EAAA,cACA,EAAgB,GAAA,cAChB,GACE,EAAO,cAAgB,GAE3B,IAAI,EACA,EACA,GACF,EACE,qEACF,EAAO,CAAC,EAAW,EAAe,KAElC,EACE,kFACF,EAAO,CAAC,EAAW,IAQrB,MAAO,UALc,KAAK,KAAK,MAC7B,KAAK,eAAe,WAAa,EACjC,IAGmB,KACrB,QAAY,IAAR,EAAmB,OAEvB,GAAI,EAAI,WAAW,EAAI,GAAiC,MAA5B,EAAI,qBAA8B,CAQ5D,MAAO,UAPmB,KAAK,KAAK,MAElC,KAAK,eAAe,yBAA0B,CAC9C,EACA,CAAC,EAAI,yBAGwB,KACf,MAAZ,SACI,KAAK,qBAAqB,EAAS,cAAe,E,CAI5D,MAAM,QAAmB,KAAK,gBAC5B,EAAI,WACJ,EAAI,gBAsBN,MAAO,CACL,OApBkB,CAClB,aAAc,CACZ,YACA,gBACA,cAAe,EAAI,gBAiBrB,aACA,eAfqB,KAAK,cAAc,EAAI,UAgB5C,aAfmB,EAAI,qBACrB,CACE,aAAc,CACZ,YACA,gBACA,cAAe,EAAI,4BAGvB,EAQF,oBAP0B,KAAK,YAAY,EAAI,gB,CAiBnD,UAAO,CACL,EACA,GAEA,MAAM,OAAE,EAAA,OAAQ,EAAA,MAAQ,GAAU,GAAW,IACtC,EAAO,GAAQ,KAAK,aAAa,EAAQ,EAAQ,GACxD,IAAI,EAAQ,GAAG,KAAK,eAAe,aAAa,qCAClC,IAAV,IACF,GAAS,UAAU,OAAO,SAAS,EAAM,WAAY,OAGvD,MAAM,QAAe,KAAK,KAAK,MAA+B,EAAO,GAC/D,EAAY,EAAO,KAAK,QAC3B,GAAQ,EAAI,WAAW,EAAI,GAAiC,MAA5B,EAAI,uBAGvC,GAAI,EAAU,OAAS,EAAG,CACxB,MAAM,QAAoB,KAAK,KAAK,MAElC,KAAK,eAAe,yBAA0B,CAC9C,EAAU,GAAG,UACb,EAAU,KAAK,GAAQ,EAAI,yBAGvB,EAAY,EAAU,QAAA,CAEzB,EAAK,IACD,EAAI,sBAET,EAAI,EAAI,wBAA0B,GAClC,EAAI,EAAI,sBAAsB,KAAK,GAC5B,GAJ+B,GAKrC,IAGH,IAAK,MAAM,KAAY,EAAY,KACjC,IAAK,MAAM,KAAO,EAAU,EAAS,qBAC7B,KAAK,qBAAqB,EAAS,cAAe,E,CAK9D,IAAK,MAAM,KAAS,EAAO,UACnB,CACJ,OAAQ,CACN,aAAc,CACZ,UAAW,EAAM,UACjB,cAAe,EAAM,cACrB,cAAe,EAAM,gBAGzB,iBAAkB,KAAK,gBACrB,EAAM,WACN,EAAM,gBAER,eAAgB,KAAK,cAAc,EAAM,UACzC,aAAc,EAAM,qBAChB,CACE,aAAc,CACZ,UAAW,EAAM,UACjB,cAAe,EAAM,cACrB,cAAe,EAAM,4BAGzB,EACJ,oBAAqB,KAAK,YAAY,EAAM,gB,CAMlD,0BAAM,CACJ,EACA,GAKA,MAAM,EAAc,IAAI,YAClB,EAAc,IAAI,YAClB,EAAM,GAEL,EAAK,SAAc,KAAK,MAAM,iBAC7B,QAAQ,IACZ,EAAa,KAAA,EAAM,EAAK,KACtB,KAAK,MAAM,WAAW,EAAY,OAAO,GAAM,OAKrD,EAAI,iBAAmB,GACvB,EAAI,eAAe,KAAK,CACtB,EAAY,OAAO,OACnB,EAAY,OAAO,GACnB,IAIF,EAAI,WAAW,iBAAiB,OAC9B,OAAO,KAAK,EAAW,WAAW,kBAAkB,OAAS,EACzD,qBACK,OAAO,OAAO,EAAW,WAAW,mBAEzC,KAAK,oBAAe,E,CAa5B,SAAM,CACJ,EACA,EACA,EACA,GAEA,QAA4B,IAAxB,EAAO,aACT,MAAM,IAAI,MAAM,kDAElB,MAAM,UACJ,EAAA,cACA,EAAgB,GAAA,cAChB,GACE,EAAO,aAEL,EAAa,CACjB,aAAc,CACZ,YACA,gBACA,cAAe,EAAW,KAGxB,QAAe,KAAK,KAAK,UACzB,EAAuB,KAAK,gBAAgB,GAClD,UACQ,EAAO,MAAM,SACnB,MAAM,QAAwB,KAAK,WACjC,EACA,EACA,EAAW,eACX,GAEF,IAAK,MAAM,KAAkB,QACrB,EAAO,MACX,KAAK,eAAe,4BACpB,SAGE,EAAO,MAAM,KAAK,eAAe,uBAAwB,CAC7D,EACA,EACA,EAAW,GACX,EACA,QACM,KAAK,cAAc,WAErB,EAAO,MAAM,S,OACZ,GAEP,YADM,EAAO,MAAM,YACb,C,SAEN,EAAO,S,CAET,OAAO,C,CAWT,eAAM,CACJ,EACA,EACA,GAEA,MAAM,EAAQ,EAAO,OAAO,GAAM,EAAE,KAAM,iBACtC,KAAK,eAAe,6BACpB,KAAK,eAAe,6BAElB,QAAqB,KAAK,YAC9B,EAAO,cAAc,UACrB,EAAO,cAAc,cACrB,EAAO,cAAc,cACrB,EACA,GAEI,QAAe,KAAK,KAAK,UAC/B,UACQ,EAAO,MAAM,SACnB,UAAW,MAAM,KAAe,QACxB,EAAO,MAAM,EAAO,SAEtB,EAAO,MAAM,S,OACZ,GAEP,YADM,EAAO,MAAM,YACb,C,SAEN,EAAO,S,EAIX,SAAM,GACJ,OAAO,KAAK,KAAK,K,CAGnB,kBAAM,CAAa,GACjB,MAAM,QAAe,KAAK,KAAK,UAC/B,UACQ,EAAO,MAAM,eACb,EAAO,MAAM,KAAK,eAAe,4BAA6B,CAClE,UAEI,EAAO,MAAM,KAAK,eAAe,uBAAwB,CAC7D,UAEI,EAAO,MAAM,KAAK,eAAe,6BAA8B,CACnE,UAEI,EAAO,MAAM,S,OACZ,GAEP,YADM,EAAO,MAAM,YACb,C,SAEN,EAAO,S","file":"/npm/@langchain/langgraph-checkpoint-postgres@1.0.1/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@langchain/langgraph-checkpoint-postgres@1.0.1/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import type { RunnableConfig } from \"@langchain/core/runnables\";\nimport {\n  BaseCheckpointSaver,\n  type Checkpoint,\n  type CheckpointListOptions,\n  type CheckpointTuple,\n  type SerializerProtocol,\n  type PendingWrite,\n  type CheckpointMetadata,\n  type ChannelVersions,\n  WRITES_IDX_MAP,\n  TASKS,\n  maxChannelVersion,\n} from \"@langchain/langgraph-checkpoint\";\nimport pg from \"pg\";\n\nimport { getMigrations } from \"./migrations.js\";\nimport {\n  type SQL_STATEMENTS,\n  type SQL_TYPES,\n  getSQLStatements,\n  getTablesWithSchema,\n} from \"./sql.js\";\n\n/** @inline */\ninterface PostgresSaverOptions {\n  schema: string;\n}\n\nconst _defaultOptions: PostgresSaverOptions = {\n  schema: \"public\",\n};\n\nconst _ensureCompleteOptions = (\n  options?: Partial<PostgresSaverOptions>\n): PostgresSaverOptions => {\n  return {\n    ...options,\n    schema: options?.schema ?? _defaultOptions.schema,\n  };\n};\n\nconst { Pool } = pg;\n\n/**\n * LangGraph checkpointer that uses a Postgres instance as the backing store.\n * Uses the [node-postgres](https://node-postgres.com/) package internally\n * to connect to a Postgres instance.\n *\n * @example\n * ```\n * import { ChatOpenAI } from \"@langchain/openai\";\n * import { PostgresSaver } from \"@langchain/langgraph-checkpoint-postgres\";\n * import { createReactAgent } from \"@langchain/langgraph/prebuilt\";\n *\n * const checkpointer = PostgresSaver.fromConnString(\n *   \"postgresql://user:password@localhost:5432/db\",\n *   // optional configuration object\n *   {\n *     schema: \"custom_schema\" // defaults to \"public\"\n *   }\n * );\n *\n * // NOTE: you need to call .setup() the first time you're using your checkpointer\n * await checkpointer.setup();\n *\n * const graph = createReactAgent({\n *   tools: [getWeather],\n *   llm: new ChatOpenAI({\n *     model: \"gpt-4o-mini\",\n *   }),\n *   checkpointSaver: checkpointer,\n * });\n * const config = { configurable: { thread_id: \"1\" } };\n *\n * await graph.invoke({\n *   messages: [{\n *     role: \"user\",\n *     content: \"what's the weather in sf\"\n *   }],\n * }, config);\n * ```\n */\nexport class PostgresSaver extends BaseCheckpointSaver {\n  private readonly pool: pg.Pool;\n\n  private readonly options: PostgresSaverOptions;\n\n  private readonly SQL_STATEMENTS: SQL_STATEMENTS;\n\n  protected isSetup: boolean;\n\n  constructor(\n    pool: pg.Pool,\n    serde?: SerializerProtocol,\n    options?: Partial<PostgresSaverOptions>\n  ) {\n    super(serde);\n    this.pool = pool;\n    this.isSetup = false;\n    this.options = _ensureCompleteOptions(options);\n    this.SQL_STATEMENTS = getSQLStatements(this.options.schema);\n  }\n\n  /**\n   * Creates a new instance of PostgresSaver from a connection string.\n   *\n   * @param {string} connString - The connection string to connect to the Postgres database.\n   * @param {PostgresSaverOptions} [options] - Optional configuration object.\n   * @returns {PostgresSaver} A new instance of PostgresSaver.\n   *\n   * @example\n   * const connString = \"postgresql://user:password@localhost:5432/db\";\n   * const checkpointer = PostgresSaver.fromConnString(connString, {\n   *  schema: \"custom_schema\" // defaults to \"public\"\n   * });\n   * await checkpointer.setup();\n   */\n  static fromConnString(\n    connString: string,\n    options?: Partial<PostgresSaverOptions>\n  ): PostgresSaver {\n    const pool = new Pool({ connectionString: connString });\n    return new PostgresSaver(pool, undefined, options);\n  }\n\n  /**\n   * Set up the checkpoint database asynchronously.\n   *\n   * This method creates the necessary tables in the Postgres database if they don't\n   * already exist and runs database migrations. It MUST be called directly by the user\n   * the first time checkpointer is used.\n   */\n  async setup(): Promise<void> {\n    const client = await this.pool.connect();\n    const SCHEMA_TABLES = getTablesWithSchema(this.options.schema);\n    try {\n      await client.query(\n        `CREATE SCHEMA IF NOT EXISTS \"${this.options.schema}\"`\n      );\n      let version = -1;\n      const MIGRATIONS = getMigrations(this.options.schema);\n\n      try {\n        const result = await client.query(\n          `SELECT v FROM ${SCHEMA_TABLES.checkpoint_migrations} ORDER BY v DESC LIMIT 1`\n        );\n        if (result.rows.length > 0) {\n          version = result.rows[0].v;\n        }\n      } catch (error: unknown) {\n        // Assume table doesn't exist if there's an error\n        if (\n          typeof error === \"object\" &&\n          error !== null &&\n          \"code\" in error &&\n          typeof error.code === \"string\" &&\n          error.code === \"42P01\" // Postgres error code for undefined_table\n        ) {\n          version = -1;\n        } else {\n          throw error;\n        }\n      }\n\n      for (let v = version + 1; v < MIGRATIONS.length; v += 1) {\n        await client.query(MIGRATIONS[v]);\n        await client.query(\n          `INSERT INTO ${SCHEMA_TABLES.checkpoint_migrations} (v) VALUES ($1)`,\n          [v]\n        );\n      }\n    } finally {\n      client.release();\n    }\n  }\n\n  protected async _loadCheckpoint(\n    checkpoint: Omit<Checkpoint, \"pending_sends\" | \"channel_values\">,\n    channelValues: [Uint8Array, Uint8Array, Uint8Array][]\n  ): Promise<Checkpoint> {\n    return {\n      ...checkpoint,\n      channel_values: await this._loadBlobs(channelValues),\n    };\n  }\n\n  protected async _loadBlobs(\n    blobValues: [Uint8Array, Uint8Array, Uint8Array][]\n  ): Promise<Record<string, unknown>> {\n    if (!blobValues || blobValues.length === 0) {\n      return {};\n    }\n    const textDecoder = new TextDecoder();\n    const entries = await Promise.all(\n      blobValues\n        .filter(([, t]) => textDecoder.decode(t) !== \"empty\")\n        .map(async ([k, t, v]) => [\n          textDecoder.decode(k),\n          await this.serde.loadsTyped(textDecoder.decode(t), v),\n        ])\n    );\n    return Object.fromEntries(entries);\n  }\n\n  protected async _loadMetadata(metadata: Record<string, unknown>) {\n    const [type, dumpedValue] = await this.serde.dumpsTyped(metadata);\n    return this.serde.loadsTyped(type, dumpedValue);\n  }\n\n  protected async _loadWrites(\n    writes: [Uint8Array, Uint8Array, Uint8Array, Uint8Array][]\n  ): Promise<[string, string, unknown][]> {\n    const decoder = new TextDecoder();\n    return writes\n      ? await Promise.all(\n          writes.map(async ([tid, channel, t, v]) => [\n            decoder.decode(tid),\n            decoder.decode(channel),\n            await this.serde.loadsTyped(decoder.decode(t), v),\n          ])\n        )\n      : [];\n  }\n\n  protected async _dumpBlobs(\n    threadId: string,\n    checkpointNs: string,\n    values: Record<string, unknown>,\n    versions: ChannelVersions\n  ): Promise<\n    [string, string, string, string, string, Uint8Array | undefined][]\n  > {\n    if (Object.keys(versions).length === 0) {\n      return [];\n    }\n\n    return Promise.all(\n      Object.entries(versions).map(async ([k, ver]) => {\n        const [type, value] =\n          k in values\n            ? await this.serde.dumpsTyped(values[k])\n            : [\"empty\", null];\n        return [\n          threadId,\n          checkpointNs,\n          k,\n          ver.toString(),\n          type,\n          value ? new Uint8Array(value) : undefined,\n        ];\n      })\n    );\n  }\n\n  protected _dumpCheckpoint(checkpoint: Checkpoint) {\n    const serialized: Record<string, unknown> = { ...checkpoint };\n    if (\"channel_values\" in serialized) delete serialized.channel_values;\n    return serialized;\n  }\n\n  protected async _dumpMetadata(metadata: CheckpointMetadata) {\n    const [, serializedMetadata] = await this.serde.dumpsTyped(metadata);\n    // We need to remove null characters before writing\n    return JSON.parse(\n      new TextDecoder().decode(serializedMetadata).replace(/\\0/g, \"\")\n    );\n  }\n\n  protected async _dumpWrites(\n    threadId: string,\n    checkpointNs: string,\n    checkpointId: string,\n    taskId: string,\n    writes: [string, unknown][]\n  ): Promise<\n    [string, string, string, string, number, string, string, Uint8Array][]\n  > {\n    return Promise.all(\n      writes.map(async ([channel, value], idx) => {\n        const [type, serializedValue] = await this.serde.dumpsTyped(value);\n        return [\n          threadId,\n          checkpointNs,\n          checkpointId,\n          taskId,\n          WRITES_IDX_MAP[channel] ?? idx,\n          channel,\n          type,\n          new Uint8Array(serializedValue),\n        ];\n      })\n    );\n  }\n\n  /**\n   * Return WHERE clause predicates for a given list() config, filter, cursor.\n   *\n   * This method returns a tuple of a string and a tuple of values. The string\n   * is the parameterized WHERE clause predicate (including the WHERE keyword):\n   * \"WHERE column1 = $1 AND column2 IS $2\". The list of values contains the\n   * values for each of the corresponding parameters.\n   */\n  protected _searchWhere(\n    config?: RunnableConfig,\n    filter?: Record<string, unknown>,\n    before?: RunnableConfig\n  ): [string, unknown[]] {\n    const wheres: string[] = [];\n    const paramValues: unknown[] = [];\n\n    // construct predicate for config filter\n    if (config?.configurable?.thread_id) {\n      wheres.push(`thread_id = $${paramValues.length + 1}`);\n      paramValues.push(config.configurable.thread_id);\n    }\n\n    // strict checks for undefined/null because empty strings are falsy\n    if (\n      config?.configurable?.checkpoint_ns !== undefined &&\n      config?.configurable?.checkpoint_ns !== null\n    ) {\n      wheres.push(`checkpoint_ns = $${paramValues.length + 1}`);\n      paramValues.push(config.configurable.checkpoint_ns);\n    }\n\n    if (config?.configurable?.checkpoint_id) {\n      wheres.push(`checkpoint_id = $${paramValues.length + 1}`);\n      paramValues.push(config.configurable.checkpoint_id);\n    }\n\n    // construct predicate for metadata filter\n    if (filter && Object.keys(filter).length > 0) {\n      wheres.push(`metadata @> $${paramValues.length + 1}`);\n      paramValues.push(JSON.stringify(filter));\n    }\n\n    // construct predicate for `before`\n    if (before?.configurable?.checkpoint_id !== undefined) {\n      wheres.push(`checkpoint_id < $${paramValues.length + 1}`);\n      paramValues.push(before.configurable.checkpoint_id);\n    }\n\n    return [\n      wheres.length > 0 ? `WHERE ${wheres.join(\" AND \")}` : \"\",\n      paramValues,\n    ];\n  }\n\n  /**\n   * Get a checkpoint tuple from the database.\n   * This method retrieves a checkpoint tuple from the Postgres database\n   * based on the provided config. If the config's configurable field contains\n   * a \"checkpoint_id\" key, the checkpoint with the matching thread_id and\n   * namespace is retrieved. Otherwise, the latest checkpoint for the given\n   * thread_id is retrieved.\n   * @param config The config to use for retrieving the checkpoint.\n   * @returns The retrieved checkpoint tuple, or undefined.\n   */\n  async getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined> {\n    const {\n      thread_id,\n      checkpoint_ns = \"\",\n      checkpoint_id,\n    } = config.configurable ?? {};\n\n    let args: unknown[];\n    let where: string;\n    if (checkpoint_id) {\n      where =\n        \"WHERE thread_id = $1 AND checkpoint_ns = $2 AND checkpoint_id = $3\";\n      args = [thread_id, checkpoint_ns, checkpoint_id];\n    } else {\n      where =\n        \"WHERE thread_id = $1 AND checkpoint_ns = $2 ORDER BY checkpoint_id DESC LIMIT 1\";\n      args = [thread_id, checkpoint_ns];\n    }\n\n    const result = await this.pool.query<SQL_TYPES[\"SELECT_SQL\"]>(\n      this.SQL_STATEMENTS.SELECT_SQL + where,\n      args\n    );\n\n    const [row] = result.rows;\n    if (row === undefined) return undefined;\n\n    if (row.checkpoint.v < 4 && row.parent_checkpoint_id != null) {\n      const sendsResult = await this.pool.query<\n        SQL_TYPES[\"SELECT_PENDING_SENDS_SQL\"]\n      >(this.SQL_STATEMENTS.SELECT_PENDING_SENDS_SQL, [\n        thread_id,\n        [row.parent_checkpoint_id],\n      ]);\n\n      const [sendsRow] = sendsResult.rows;\n      if (sendsRow != null) {\n        await this._migratePendingSends(sendsRow.pending_sends, row);\n      }\n    }\n\n    const checkpoint = await this._loadCheckpoint(\n      row.checkpoint,\n      row.channel_values\n    );\n\n    const finalConfig = {\n      configurable: {\n        thread_id,\n        checkpoint_ns,\n        checkpoint_id: row.checkpoint_id,\n      },\n    };\n    const metadata = await this._loadMetadata(row.metadata);\n    const parentConfig = row.parent_checkpoint_id\n      ? {\n          configurable: {\n            thread_id,\n            checkpoint_ns,\n            checkpoint_id: row.parent_checkpoint_id,\n          },\n        }\n      : undefined;\n    const pendingWrites = await this._loadWrites(row.pending_writes);\n\n    return {\n      config: finalConfig,\n      checkpoint,\n      metadata,\n      parentConfig,\n      pendingWrites,\n    };\n  }\n\n  /**\n   * List checkpoints from the database.\n   *\n   * This method retrieves a list of checkpoint tuples from the Postgres database based\n   * on the provided config. The checkpoints are ordered by checkpoint ID in descending order (newest first).\n   */\n  async *list(\n    config: RunnableConfig,\n    options?: CheckpointListOptions\n  ): AsyncGenerator<CheckpointTuple> {\n    const { filter, before, limit } = options ?? {};\n    const [where, args] = this._searchWhere(config, filter, before);\n    let query = `${this.SQL_STATEMENTS.SELECT_SQL}${where} ORDER BY checkpoint_id DESC`;\n    if (limit !== undefined) {\n      query += ` LIMIT ${Number.parseInt(limit.toString(), 10)}`; // sanitize via parseInt, as limit could be an externally provided value\n    }\n\n    const result = await this.pool.query<SQL_TYPES[\"SELECT_SQL\"]>(query, args);\n    const toMigrate = result.rows.filter(\n      (row) => row.checkpoint.v < 4 && row.parent_checkpoint_id != null\n    );\n\n    if (toMigrate.length > 0) {\n      const sendsResult = await this.pool.query<\n        SQL_TYPES[\"SELECT_PENDING_SENDS_SQL\"]\n      >(this.SQL_STATEMENTS.SELECT_PENDING_SENDS_SQL, [\n        toMigrate[0].thread_id,\n        toMigrate.map((row) => row.parent_checkpoint_id),\n      ]);\n\n      const parentMap = toMigrate.reduce<\n        Record<string, SQL_TYPES[\"SELECT_SQL\"][]>\n      >((acc, row) => {\n        if (!row.parent_checkpoint_id) return acc;\n\n        acc[row.parent_checkpoint_id] ??= [];\n        acc[row.parent_checkpoint_id].push(row);\n        return acc;\n      }, {});\n\n      // add to values\n      for (const sendsRow of sendsResult.rows) {\n        for (const row of parentMap[sendsRow.checkpoint_id]) {\n          await this._migratePendingSends(sendsRow.pending_sends, row);\n        }\n      }\n    }\n\n    for (const value of result.rows) {\n      yield {\n        config: {\n          configurable: {\n            thread_id: value.thread_id,\n            checkpoint_ns: value.checkpoint_ns,\n            checkpoint_id: value.checkpoint_id,\n          },\n        },\n        checkpoint: await this._loadCheckpoint(\n          value.checkpoint,\n          value.channel_values\n        ),\n        metadata: await this._loadMetadata(value.metadata),\n        parentConfig: value.parent_checkpoint_id\n          ? {\n              configurable: {\n                thread_id: value.thread_id,\n                checkpoint_ns: value.checkpoint_ns,\n                checkpoint_id: value.parent_checkpoint_id,\n              },\n            }\n          : undefined,\n        pendingWrites: await this._loadWrites(value.pending_writes),\n      };\n    }\n  }\n\n  /** @internal */\n  async _migratePendingSends(\n    pendingSends: [Uint8Array, Uint8Array][],\n    mutableRow: {\n      channel_values: [Uint8Array, Uint8Array, Uint8Array][];\n      checkpoint: Omit<Checkpoint, \"pending_sends\" | \"channel_values\">;\n    }\n  ) {\n    const textEncoder = new TextEncoder();\n    const textDecoder = new TextDecoder();\n    const row = mutableRow;\n\n    const [enc, blob] = await this.serde.dumpsTyped(\n      await Promise.all(\n        pendingSends.map(([enc, blob]) =>\n          this.serde.loadsTyped(textDecoder.decode(enc), blob)\n        )\n      )\n    );\n\n    row.channel_values ??= [];\n    row.channel_values.push([\n      textEncoder.encode(TASKS),\n      textEncoder.encode(enc),\n      blob,\n    ]);\n\n    // add to versions\n    row.checkpoint.channel_versions[TASKS] =\n      Object.keys(mutableRow.checkpoint.channel_versions).length > 0\n        ? maxChannelVersion(\n            ...Object.values(mutableRow.checkpoint.channel_versions)\n          )\n        : this.getNextVersion(undefined);\n  }\n\n  /**\n   * Save a checkpoint to the database.\n   *\n   * This method saves a checkpoint to the Postgres database. The checkpoint is associated\n   * with the provided config and its parent config (if any).\n   * @param config\n   * @param checkpoint\n   * @param metadata\n   * @returns\n   */\n  async put(\n    config: RunnableConfig,\n    checkpoint: Checkpoint,\n    metadata: CheckpointMetadata,\n    newVersions: ChannelVersions\n  ): Promise<RunnableConfig> {\n    if (config.configurable === undefined) {\n      throw new Error(`Missing \"configurable\" field in \"config\" param`);\n    }\n    const {\n      thread_id,\n      checkpoint_ns = \"\",\n      checkpoint_id,\n    } = config.configurable;\n\n    const nextConfig = {\n      configurable: {\n        thread_id,\n        checkpoint_ns,\n        checkpoint_id: checkpoint.id,\n      },\n    };\n    const client = await this.pool.connect();\n    const serializedCheckpoint = this._dumpCheckpoint(checkpoint);\n    try {\n      await client.query(\"BEGIN\");\n      const serializedBlobs = await this._dumpBlobs(\n        thread_id,\n        checkpoint_ns,\n        checkpoint.channel_values,\n        newVersions\n      );\n      for (const serializedBlob of serializedBlobs) {\n        await client.query(\n          this.SQL_STATEMENTS.UPSERT_CHECKPOINT_BLOBS_SQL,\n          serializedBlob\n        );\n      }\n      await client.query(this.SQL_STATEMENTS.UPSERT_CHECKPOINTS_SQL, [\n        thread_id,\n        checkpoint_ns,\n        checkpoint.id,\n        checkpoint_id,\n        serializedCheckpoint,\n        await this._dumpMetadata(metadata),\n      ]);\n      await client.query(\"COMMIT\");\n    } catch (e) {\n      await client.query(\"ROLLBACK\");\n      throw e;\n    } finally {\n      client.release();\n    }\n    return nextConfig;\n  }\n\n  /**\n   * Store intermediate writes linked to a checkpoint.\n   *\n   * This method saves intermediate writes associated with a checkpoint to the Postgres database.\n   * @param config Configuration of the related checkpoint.\n   * @param writes List of writes to store.\n   * @param taskId Identifier for the task creating the writes.\n   */\n  async putWrites(\n    config: RunnableConfig,\n    writes: PendingWrite[],\n    taskId: string\n  ): Promise<void> {\n    const query = writes.every((w) => w[0] in WRITES_IDX_MAP)\n      ? this.SQL_STATEMENTS.UPSERT_CHECKPOINT_WRITES_SQL\n      : this.SQL_STATEMENTS.INSERT_CHECKPOINT_WRITES_SQL;\n\n    const dumpedWrites = await this._dumpWrites(\n      config.configurable?.thread_id,\n      config.configurable?.checkpoint_ns,\n      config.configurable?.checkpoint_id,\n      taskId,\n      writes\n    );\n    const client = await this.pool.connect();\n    try {\n      await client.query(\"BEGIN\");\n      for await (const dumpedWrite of dumpedWrites) {\n        await client.query(query, dumpedWrite);\n      }\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  }\n\n  async end() {\n    return this.pool.end();\n  }\n\n  async deleteThread(threadId: string): Promise<void> {\n    const client = await this.pool.connect();\n    try {\n      await client.query(\"BEGIN\");\n      await client.query(this.SQL_STATEMENTS.DELETE_CHECKPOINT_BLOBS_SQL, [\n        threadId,\n      ]);\n      await client.query(this.SQL_STATEMENTS.DELETE_CHECKPOINTS_SQL, [\n        threadId,\n      ]);\n      await client.query(this.SQL_STATEMENTS.DELETE_CHECKPOINT_WRITES_SQL, [\n        threadId,\n      ]);\n      await client.query(\"COMMIT\");\n    } catch (error) {\n      await client.query(\"ROLLBACK\");\n      throw error;\n    } finally {\n      client.release();\n    }\n  }\n}\n"]}