{"version":3,"file":"test_utils.cjs","names":["TASKS"],"sources":["../src/test_utils.ts"],"sourcesContent":["import {\n  BaseCheckpointSaver,\n  ChannelVersions,\n  CheckpointPendingWrite,\n  PendingWrite,\n  TASKS,\n  uuid6,\n  type CheckpointTuple,\n} from \"@langchain/langgraph-checkpoint\";\n\n// to make the type signature of the skipOnModules function a bit more readable\nexport type CheckpointerName = string;\nexport type WhySkipped = string;\n\n/**\n * Conditionally skips a test for a specific checkpointer implementation. When the test is skipped, the reason for\n * skipping is provided.\n *\n * @param checkpointerName - The name of the current module being tested (as passed via the `name` argument in the top-level suite entrypoint).\n * @param skippedCheckpointers - A list of modules for which the test should be skipped.\n * @returns A function that can be used in place of the Vitest @see it function and conditionally skips the test for the provided module.\n */\nexport function it_skipForSomeModules(\n  checkpointerName: string,\n  skippedCheckpointers: Record<CheckpointerName, WhySkipped>\n): typeof it | typeof it.skip {\n  const skipReason = skippedCheckpointers[checkpointerName];\n\n  if (skipReason) {\n    const skip = (...args: Parameters<typeof it.skip>) => {\n      const [name, test, timeout] = args;\n      it.skip(`[because ${skipReason}] ${name}`, test, timeout);\n    };\n    skip.prototype = it.skip.prototype;\n    return skip as typeof it.skip;\n  }\n\n  return it;\n}\n\nexport interface InitialCheckpointTupleConfig {\n  thread_id: string;\n  checkpoint_id: string;\n  checkpoint_ns: string;\n  channel_values?: Record<string, unknown>;\n  channel_versions?: ChannelVersions;\n}\nexport function initialCheckpointTuple({\n  thread_id,\n  checkpoint_id,\n  checkpoint_ns,\n  channel_values = {},\n}: InitialCheckpointTupleConfig): CheckpointTuple {\n  if (checkpoint_ns === undefined) {\n    throw new Error(\"checkpoint_ns is required\");\n  }\n\n  const channel_versions = Object.fromEntries(\n    Object.keys(channel_values).map((key) => [key, 1])\n  );\n\n  const config = {\n    configurable: {\n      thread_id,\n      checkpoint_id,\n      checkpoint_ns,\n    },\n  };\n\n  return {\n    config,\n    checkpoint: {\n      v: 4,\n      ts: new Date().toISOString(),\n      id: checkpoint_id,\n      channel_values,\n      channel_versions,\n      versions_seen: {\n        // this is meant to be opaque to checkpointers, so we just stuff dummy data in here to make sure it's stored and retrieved\n        \"\": { someChannel: 1 },\n      },\n    },\n\n    metadata: {\n      source: \"input\",\n      step: -1,\n      parents: {},\n    },\n  };\n}\n\nexport interface ParentAndChildCheckpointTuplesWithWritesConfig {\n  thread_id: string;\n  parentCheckpointId: string;\n  childCheckpointId: string;\n  checkpoint_ns: string;\n  initialChannelValues?: Record<string, unknown>;\n  writesToParent?: { taskId: string; writes: PendingWrite[] }[];\n  writesToChild?: { taskId: string; writes: PendingWrite[] }[];\n}\n\nexport function parentAndChildCheckpointTuplesWithWrites({\n  thread_id,\n  parentCheckpointId,\n  childCheckpointId,\n  checkpoint_ns,\n  initialChannelValues = {},\n  writesToParent = [],\n  writesToChild = [],\n}: ParentAndChildCheckpointTuplesWithWritesConfig): {\n  parent: CheckpointTuple;\n  child: CheckpointTuple;\n} {\n  if (checkpoint_ns === undefined) {\n    throw new Error(\"checkpoint_ns is required\");\n  }\n\n  const parentChannelVersions = Object.fromEntries(\n    Object.keys(initialChannelValues).map((key) => [key, 1])\n  );\n\n  const parentPendingWrites = writesToParent.flatMap(({ taskId, writes }) =>\n    writes.map(\n      ([channel, value]) => [taskId, channel, value] as CheckpointPendingWrite\n    )\n  );\n\n  const composedChildWritesByChannel = writesToChild.reduce(\n    (acc, { writes }) => {\n      writes.forEach(([channel, value]) => {\n        acc[channel] = [channel, value];\n      });\n      return acc;\n    },\n    {} as Record<string, PendingWrite>\n  );\n\n  const childWriteCountByChannel = writesToChild.reduce(\n    (acc, { writes }) => {\n      writes.forEach(([channel, _]) => {\n        acc[channel] = (acc[channel] || 0) + 1;\n      });\n      return acc;\n    },\n    {} as Record<string, number>\n  );\n\n  const childChannelVersions = Object.fromEntries(\n    Object.entries(parentChannelVersions).map(([key, value]) => [\n      key,\n      key in childWriteCountByChannel\n        ? value + childWriteCountByChannel[key]\n        : value,\n    ])\n  );\n\n  const childPendingWrites = writesToChild.flatMap(({ taskId, writes }) =>\n    writes.map(\n      ([channel, value]) => [taskId, channel, value] as CheckpointPendingWrite\n    )\n  );\n\n  const childChannelValues = {\n    ...initialChannelValues,\n    ...composedChildWritesByChannel,\n  };\n\n  return {\n    parent: {\n      checkpoint: {\n        v: 4,\n        ts: new Date().toISOString(),\n        id: parentCheckpointId,\n        channel_values: initialChannelValues,\n        channel_versions: parentChannelVersions,\n        versions_seen: {\n          // this is meant to be opaque to checkpointers, so we just stuff dummy data in here to make sure it's stored and retrieved\n          \"\": {\n            someChannel: 1,\n          },\n        },\n      },\n      metadata: {\n        source: \"input\",\n        step: -1,\n        parents: {},\n      },\n      config: {\n        configurable: {\n          thread_id,\n          checkpoint_ns,\n          checkpoint_id: parentCheckpointId,\n        },\n      },\n      parentConfig: undefined,\n      pendingWrites: parentPendingWrites,\n    },\n    child: {\n      checkpoint: {\n        v: 4,\n        ts: new Date().toISOString(),\n        id: childCheckpointId,\n        channel_values: childChannelValues,\n        channel_versions: childChannelVersions,\n        versions_seen: {\n          // this is meant to be opaque to checkpointers, so we just stuff dummy data in here to make sure it's stored and retrieved\n          \"\": {\n            someChannel: 1,\n          },\n        },\n        // pending_sends,\n      },\n      metadata: {\n        source: \"loop\",\n        step: 0,\n        parents: {\n          [checkpoint_ns]: parentCheckpointId,\n        },\n      },\n      config: {\n        configurable: {\n          thread_id,\n          checkpoint_ns,\n          checkpoint_id: childCheckpointId,\n        },\n      },\n      parentConfig: {\n        configurable: {\n          thread_id,\n          checkpoint_ns,\n          checkpoint_id: parentCheckpointId,\n        },\n      },\n      pendingWrites: childPendingWrites,\n    },\n  };\n}\n\nexport function* generateTuplePairs(\n  countPerNamespace: number,\n  namespaces: string[]\n): Generator<{\n  tuple: CheckpointTuple;\n  writes: { writes: PendingWrite[]; taskId: string }[];\n  newVersions: Record<string, number | string>;\n}> {\n  for (let i = 0; i < countPerNamespace; i += 1) {\n    const thread_id = uuid6(3);\n    for (const checkpoint_ns of namespaces) {\n      const parentCheckpointId = uuid6(3);\n      const childCheckpointId = uuid6(3);\n\n      const writesToParent = [\n        {\n          writes: [[TASKS, [\"add_fish\"]]] as PendingWrite[],\n          taskId: \"pending_sends_task\",\n        },\n      ];\n      const writesToChild = [\n        {\n          writes: [[\"animals\", [\"fish\", \"dog\"]]] as PendingWrite[],\n          taskId: \"add_fish\",\n        },\n      ];\n      const initialChannelValues = {\n        animals: [\"dog\"],\n      };\n\n      const { parent, child } = parentAndChildCheckpointTuplesWithWrites({\n        thread_id,\n        checkpoint_ns,\n        parentCheckpointId,\n        childCheckpointId,\n        initialChannelValues,\n        writesToParent,\n        writesToChild,\n      });\n\n      yield {\n        tuple: parent,\n        writes: writesToParent,\n        newVersions: parent.checkpoint.channel_versions,\n      };\n      yield {\n        tuple: child,\n        writes: writesToChild,\n        newVersions: Object.fromEntries(\n          Object.entries(child.checkpoint.channel_versions).filter(\n            ([key, ver]) => parent.checkpoint.channel_versions[key] !== ver\n          )\n        ) as Record<string, number | string>,\n      };\n    }\n  }\n}\n\nexport async function* putTuples(\n  checkpointer: BaseCheckpointSaver,\n  generatedTuples: {\n    tuple: CheckpointTuple;\n    writes: { writes: PendingWrite[]; taskId: string }[];\n    newVersions: Record<string, number | string>;\n  }[]\n): AsyncGenerator<CheckpointTuple> {\n  for (const generated of generatedTuples) {\n    const { thread_id, checkpoint_ns } = generated.tuple.config\n      .configurable as { thread_id: string; checkpoint_ns: string };\n\n    const checkpoint_id = generated.tuple.parentConfig?.configurable\n      ?.checkpoint_id as string | undefined;\n\n    const config = {\n      configurable: {\n        thread_id,\n        checkpoint_ns,\n        checkpoint_id,\n      },\n    };\n\n    const existingTuple = await checkpointer.getTuple(generated.tuple.config);\n\n    expect(existingTuple).toBeUndefined();\n\n    const newConfig = await checkpointer.put(\n      config,\n      generated.tuple.checkpoint,\n      generated.tuple.metadata!,\n      generated.newVersions\n    );\n\n    for (const write of generated.writes) {\n      await checkpointer.putWrites(newConfig, write.writes, write.taskId);\n    }\n\n    const expectedTuple = await checkpointer.getTuple(newConfig);\n\n    expect(expectedTuple).not.toBeUndefined();\n\n    if (expectedTuple) {\n      yield expectedTuple;\n    }\n  }\n}\n\nexport async function toArray(\n  generator: AsyncGenerator<CheckpointTuple>\n): Promise<CheckpointTuple[]> {\n  const result = [];\n  for await (const item of generator) {\n    result.push(item);\n  }\n  return result;\n}\n\nexport function toMap(tuples: CheckpointTuple[]): Map<string, CheckpointTuple> {\n  const result = new Map<string, CheckpointTuple>();\n  for (const item of tuples) {\n    const key = item.checkpoint.id;\n    result.set(key, item);\n  }\n  return result;\n}\n"],"mappings":"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"}