{"version":3,"file":"base.cjs","names":["uuid6","JsonPlusSerializer","ERROR","SCHEDULED","INTERRUPT","RESUME"],"sources":["../src/base.ts"],"sourcesContent":["import type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { SerializerProtocol } from \"./serde/base.js\";\nimport { uuid6 } from \"./id.js\";\nimport type {\n  PendingWrite,\n  CheckpointPendingWrite,\n  CheckpointMetadata,\n  DeltaChannelHistory,\n} from \"./types.js\";\nimport { ERROR, INTERRUPT, RESUME, SCHEDULED } from \"./serde/types.js\";\nimport { JsonPlusSerializer } from \"./serde/jsonplus.js\";\n\n/** @inline */\ntype ChannelVersion = number | string;\n\nexport type ChannelVersions = Record<string, ChannelVersion>;\n\nexport interface Checkpoint<\n  N extends string = string,\n  C extends string = string,\n> {\n  /**\n   * The version of the checkpoint format. Currently 4\n   */\n  v: number;\n  /**\n   * Checkpoint ID {uuid6}\n   */\n  id: string;\n  /**\n   * Timestamp {new Date().toISOString()}\n   */\n  ts: string;\n  /**\n   * @default {}\n   */\n  channel_values: Record<C, unknown>;\n  /**\n   * @default {}\n   */\n  channel_versions: Record<C, ChannelVersion>;\n  /**\n   * @default {}\n   */\n  versions_seen: Record<N, Record<C, ChannelVersion>>;\n}\n\nexport interface ReadonlyCheckpoint extends Readonly<Checkpoint> {\n  readonly channel_values: Readonly<Record<string, unknown>>;\n  readonly channel_versions: Readonly<Record<string, ChannelVersion>>;\n  readonly versions_seen: Readonly<\n    Record<string, Readonly<Record<string, ChannelVersion>>>\n  >;\n}\n\nexport function deepCopy<T>(obj: T): T {\n  if (typeof obj !== \"object\" || obj === null) {\n    return obj;\n  }\n\n  const newObj = Array.isArray(obj) ? [] : {};\n\n  for (const key in obj) {\n    if (Object.prototype.hasOwnProperty.call(obj, key)) {\n      (newObj as Record<PropertyKey, unknown>)[key] = deepCopy(\n        (obj as Record<string, unknown>)[key]\n      );\n    }\n  }\n\n  return newObj as T;\n}\n\n/** @hidden */\nexport function emptyCheckpoint(): Checkpoint {\n  return {\n    v: 4,\n    id: uuid6(0),\n    ts: new Date().toISOString(),\n    channel_values: {},\n    channel_versions: {},\n    versions_seen: {},\n  };\n}\n\n/** @hidden */\nexport function copyCheckpoint(checkpoint: ReadonlyCheckpoint): Checkpoint {\n  return {\n    v: checkpoint.v,\n    id: checkpoint.id,\n    ts: checkpoint.ts,\n    channel_values: { ...(checkpoint.channel_values ?? {}) },\n    channel_versions: { ...(checkpoint.channel_versions ?? {}) },\n    versions_seen: deepCopy(checkpoint.versions_seen ?? {}),\n  };\n}\n\nexport interface CheckpointTuple {\n  config: RunnableConfig;\n  checkpoint: Checkpoint;\n  metadata?: CheckpointMetadata;\n  parentConfig?: RunnableConfig;\n  pendingWrites?: CheckpointPendingWrite[];\n}\n\nexport type CheckpointListOptions = {\n  limit?: number;\n  before?: RunnableConfig;\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  filter?: Record<string, any>;\n};\n\nexport abstract class BaseCheckpointSaver<V extends string | number = number> {\n  serde: SerializerProtocol = new JsonPlusSerializer();\n\n  constructor(serde?: SerializerProtocol) {\n    this.serde = serde || this.serde;\n  }\n\n  /**\n   * Prevent `JSON.stringify` from traversing backend clients (e.g. pg Pool\n   * timers) when a checkpointer is present in runnable `configurable`.\n   */\n  toJSON(): string {\n    return `[${this.constructor.name}]`;\n  }\n\n  async get(config: RunnableConfig): Promise<Checkpoint | undefined> {\n    const value = await this.getTuple(config);\n    return value ? value.checkpoint : undefined;\n  }\n\n  abstract getTuple(\n    config: RunnableConfig\n  ): Promise<CheckpointTuple | undefined>;\n\n  abstract list(\n    config: RunnableConfig,\n    options?: CheckpointListOptions\n  ): AsyncGenerator<CheckpointTuple>;\n\n  abstract put(\n    config: RunnableConfig,\n    checkpoint: Checkpoint,\n    metadata: CheckpointMetadata,\n    newVersions: ChannelVersions\n  ): Promise<RunnableConfig>;\n\n  /**\n   * Store intermediate writes linked to a checkpoint.\n   */\n  abstract putWrites(\n    config: RunnableConfig,\n    writes: PendingWrite[],\n    taskId: string\n  ): Promise<void>;\n\n  /**\n   * Delete all checkpoints and writes associated with a specific thread ID.\n   * @param threadId The thread ID whose checkpoints should be deleted.\n   */\n  abstract deleteThread(threadId: string): Promise<void>;\n\n  /**\n   * Walk the parent chain returning per-channel writes + seed, used to\n   * reconstruct `DeltaChannel` state from `checkpoint_writes`.\n   *\n   * For each requested channel, walks ancestors of the checkpoint identified\n   * by `config` (following `parentConfig`) and accumulates the pending writes\n   * for that channel. The walk terminates per-channel at the nearest ancestor\n   * whose `channel_values[ch]` is populated; that value is returned as `seed`.\n   * If the walk reaches the root without finding a stored value, `seed` is\n   * omitted from that channel's entry — the consumer treats the absence as\n   * \"start empty\".\n   *\n   * Walks the parent chain (not `list({ before })`): for forked threads, only\n   * on-path ancestors contribute.\n   *\n   * The default implementation walks `getTuple` + `parentConfig` once for all\n   * channels — each ancestor visited once, not once per channel. Savers with\n   * direct storage access (e.g. `MemorySaver`) override for performance; the\n   * return contract is fixed here.\n   *\n   * @remarks Beta. The signature, return shape, and interaction with\n   * `DeltaSnapshot` blobs may change. Override at your own risk; the default\n   * implementation will continue to work against the public\n   * `BaseCheckpointSaver` contract.\n   *\n   * @param options.config Configuration identifying the target checkpoint.\n   * @param options.channels Channel names to walk for. Empty → empty mapping.\n   * @returns Per-channel {@link DeltaChannelHistory} for every requested name.\n   */\n  async getDeltaChannelHistory(options: {\n    config: RunnableConfig;\n    channels: string[];\n  }): Promise<Record<string, DeltaChannelHistory>> {\n    const { config, channels } = options;\n    if (channels.length === 0) return {};\n\n    const collectedByCh: Record<string, CheckpointPendingWrite[]> = {};\n    const seedByCh: Record<string, unknown> = {};\n    const remaining = new Set(channels);\n    for (const ch of channels) collectedByCh[ch] = [];\n\n    const targetTuple = await this.getTuple(config);\n    let cursorConfig: RunnableConfig | undefined = targetTuple?.parentConfig;\n\n    while (cursorConfig != null && remaining.size > 0) {\n      const tup: CheckpointTuple | undefined =\n        await this.getTuple(cursorConfig);\n      if (tup === undefined) break;\n      if (tup.pendingWrites && tup.pendingWrites.length > 0) {\n        // DeltaChannel reconstruction must replay concurrent same-superstep\n        // writes in the canonical (task_id, idx) order that live execution uses\n        // (see `_applyWrites`), or the reconstructed value can diverge from the\n        // live one. Group per channel and stable-sort by task id: a stable sort\n        // keeps each task's writes in their stored `idx` order, making the\n        // result independent of how a saver returns `pendingWrites`.\n        const perChannel: Record<string, CheckpointPendingWrite[]> = {};\n        for (const write of tup.pendingWrites) {\n          const ch = write[1];\n          if (remaining.has(ch)) (perChannel[ch] ??= []).push(write);\n        }\n        for (const ch of Object.keys(perChannel)) {\n          const block = perChannel[ch];\n          block.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));\n          // Pushed reversed so the final `.reverse()` below yields oldest→newest\n          // checkpoints with each checkpoint's writes ascending by (task_id, idx).\n          for (let i = block.length - 1; i >= 0; i -= 1) {\n            collectedByCh[ch].push(block[i]);\n          }\n        }\n      }\n      for (const ch of Array.from(remaining)) {\n        if (\n          Object.prototype.hasOwnProperty.call(\n            tup.checkpoint.channel_values,\n            ch\n          )\n        ) {\n          seedByCh[ch] = tup.checkpoint.channel_values[ch];\n          remaining.delete(ch);\n        }\n      }\n      cursorConfig = tup.parentConfig;\n    }\n\n    const result: Record<string, DeltaChannelHistory> = {};\n    for (const ch of channels) {\n      const entry: DeltaChannelHistory = {\n        writes: collectedByCh[ch].slice().reverse(),\n      };\n      if (Object.prototype.hasOwnProperty.call(seedByCh, ch)) {\n        entry.seed = seedByCh[ch];\n      }\n      result[ch] = entry;\n    }\n    return result;\n  }\n\n  /**\n   * Generate the next version ID for a channel.\n   *\n   * Default is to use integer versions, incrementing by 1. If you override, you can use str/int/float versions,\n   * as long as they are monotonically increasing.\n   */\n  getNextVersion(current: V | undefined): V {\n    if (typeof current === \"string\") {\n      throw new Error(\"Please override this method to use string versions.\");\n    }\n    return (\n      current !== undefined && typeof current === \"number\" ? current + 1 : 1\n    ) as V;\n  }\n}\n\nexport function compareChannelVersions(\n  a: ChannelVersion,\n  b: ChannelVersion\n): number {\n  if (typeof a === \"number\" && typeof b === \"number\") {\n    return Math.sign(a - b);\n  }\n\n  return String(a).localeCompare(String(b));\n}\n\nexport function maxChannelVersion(\n  ...versions: ChannelVersion[]\n): ChannelVersion {\n  return versions.reduce((max, version, idx) => {\n    if (idx === 0) return version;\n    return compareChannelVersions(max, version) >= 0 ? max : version;\n  });\n}\n\n/**\n * Mapping from error type to error index.\n * Regular writes just map to their index in the list of writes being saved.\n * Special writes (e.g. errors) map to negative indices, to avoid those writes from\n * conflicting with regular writes.\n * Each Checkpointer implementation should use this mapping in put_writes.\n */\nexport const WRITES_IDX_MAP: Record<string, number> = {\n  [ERROR]: -1,\n  [SCHEDULED]: -2,\n  [INTERRUPT]: -3,\n  [RESUME]: -4,\n};\n\n/**\n * Metadata keys that are LangGraph's internal framework bookkeeping and\n * should not be surfaced as user-meaningful metadata.\n *\n * Consumed by stream handlers (e.g. the `tasks` debug stream) to drop\n * framework keys — which are redundant with a task's own fields and\n * namespace — while keeping keys like `lc_agent_name`, `ls_integration`,\n * and user-supplied metadata.\n */\nexport const EXCLUDED_METADATA_KEYS: ReadonlySet<string> = new Set([\n  \"thread_id\",\n  \"checkpoint_id\",\n  \"checkpoint_ns\",\n  \"checkpoint_map\",\n  \"langgraph_step\",\n  \"langgraph_node\",\n  \"langgraph_triggers\",\n  \"langgraph_path\",\n  \"langgraph_checkpoint_ns\",\n]);\n\nexport function getCheckpointId(config: RunnableConfig): string {\n  return (\n    config.configurable?.checkpoint_id || config.configurable?.thread_ts || \"\"\n  );\n}\n"],"mappings":"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"}