{"version":3,"file":"put.cjs","names":["initialCheckpointTuple","putTuples"],"sources":["../../src/spec/put.ts"],"sourcesContent":["import {\n  Checkpoint,\n  CheckpointMetadata,\n  CheckpointTuple,\n  uuid6,\n  type BaseCheckpointSaver,\n} from \"@langchain/langgraph-checkpoint\";\nimport { RunnableConfig } from \"@langchain/core/runnables\";\nimport { CheckpointerTestInitializer } from \"../types.js\";\nimport {\n  initialCheckpointTuple,\n  it_skipForSomeModules,\n  putTuples,\n} from \"../test_utils.js\";\n\nexport function putTests<T extends BaseCheckpointSaver>(\n  initializer: CheckpointerTestInitializer<T>\n) {\n  describe(`${initializer.checkpointerName}#put`, () => {\n    let checkpointer: T;\n    let thread_id: string;\n    let checkpoint_id1: string;\n\n    beforeEach(async () => {\n      thread_id = uuid6(3);\n      checkpoint_id1 = uuid6(3);\n      checkpointer = await initializer.createCheckpointer();\n    });\n\n    afterEach(async () => {\n      await initializer.destroyCheckpointer?.(checkpointer);\n    });\n\n    describe.each([\"root\", \"child\"])(\"namespace: %s\", (namespace) => {\n      const checkpoint_ns = namespace === \"root\" ? \"\" : namespace;\n      let checkpointStoredWithoutIdInConfig: Checkpoint;\n      let metadataStoredWithoutIdInConfig: CheckpointMetadata | undefined;\n\n      describe(\"success cases\", () => {\n        let basicPutReturnedConfig: RunnableConfig;\n        let basicPutRoundTripTuple: CheckpointTuple | undefined;\n\n        beforeEach(async () => {\n          ({\n            checkpoint: checkpointStoredWithoutIdInConfig,\n            metadata: metadataStoredWithoutIdInConfig,\n          } = initialCheckpointTuple({\n            thread_id,\n            checkpoint_id: checkpoint_id1,\n            checkpoint_ns,\n          }));\n\n          // validate assumptions - the test checkpoints must not already exist\n          const existingCheckpoint1 = await checkpointer.get({\n            configurable: {\n              thread_id,\n              checkpoint_ns,\n              checkpoint_id: checkpoint_id1,\n            },\n          });\n\n          const existingCheckpoint2 = await checkpointer.get({\n            configurable: {\n              thread_id,\n              checkpoint_ns,\n              checkpoint_id: checkpoint_id1,\n            },\n          });\n\n          expect(existingCheckpoint1).toBeUndefined();\n          expect(existingCheckpoint2).toBeUndefined();\n\n          // set up\n          // call put without the `checkpoint_id` in the config\n          basicPutReturnedConfig = await checkpointer.put(\n            {\n              configurable: {\n                thread_id,\n                checkpoint_ns,\n                // adding this to ensure that additional fields are not stored in the checkpoint tuple\n                canary: \"tweet\",\n              },\n            },\n            checkpointStoredWithoutIdInConfig,\n            metadataStoredWithoutIdInConfig!,\n            {}\n          );\n\n          basicPutRoundTripTuple = await checkpointer.getTuple(\n            basicPutReturnedConfig\n          );\n        });\n\n        it(\"should return a config with a 'configurable' property\", () => {\n          expect(basicPutReturnedConfig.configurable).toBeDefined();\n        });\n\n        it(\"should return a config with only thread_id, checkpoint_ns, and checkpoint_id in the configurable\", () => {\n          expect(\n            Object.keys(basicPutReturnedConfig.configurable ?? {})\n          ).toEqual(\n            expect.arrayContaining([\n              \"thread_id\",\n              \"checkpoint_ns\",\n              \"checkpoint_id\",\n            ])\n          );\n        });\n\n        it(\"should return config with matching thread_id\", () => {\n          expect(basicPutReturnedConfig.configurable?.thread_id).toEqual(\n            thread_id\n          );\n        });\n\n        it(\"should return config with matching checkpoint_id\", () => {\n          expect(basicPutReturnedConfig.configurable?.checkpoint_id).toEqual(\n            checkpointStoredWithoutIdInConfig.id\n          );\n        });\n\n        it(\"should return config with matching checkpoint_ns\", () => {\n          expect(basicPutReturnedConfig.configurable?.checkpoint_ns).toEqual(\n            checkpoint_ns\n          );\n        });\n\n        it(\"should result in a retrievable checkpoint tuple\", () => {\n          expect(basicPutRoundTripTuple).not.toBeUndefined();\n        });\n\n        it(\"should store the checkpoint without alteration\", () => {\n          expect(basicPutRoundTripTuple?.checkpoint).toEqual(\n            checkpointStoredWithoutIdInConfig\n          );\n        });\n\n        it(\"should store the metadata without alteration\", () => {\n          expect(basicPutRoundTripTuple?.metadata).toEqual(\n            metadataStoredWithoutIdInConfig\n          );\n        });\n      });\n\n      describe(\"failure cases\", () => {\n        it(\"should fail if config.configurable is missing\", async () => {\n          const missingConfigurableConfig: RunnableConfig = {};\n\n          await expect(\n            async () =>\n              await checkpointer.put(\n                missingConfigurableConfig,\n                checkpointStoredWithoutIdInConfig,\n                metadataStoredWithoutIdInConfig!,\n                {}\n              )\n          ).rejects.toThrow();\n        });\n\n        it(\"should fail if the thread_id is missing\", async () => {\n          const missingThreadIdConfig: RunnableConfig = {\n            configurable: {\n              checkpoint_ns,\n            },\n          };\n\n          await expect(\n            async () =>\n              await checkpointer.put(\n                missingThreadIdConfig,\n                checkpointStoredWithoutIdInConfig,\n                metadataStoredWithoutIdInConfig!,\n                {}\n              )\n          ).rejects.toThrow();\n        });\n      });\n    });\n\n    it(\"should default to empty namespace if the checkpoint namespace is missing from config.configurable\", async () => {\n      const missingNamespaceConfig: RunnableConfig = {\n        configurable: { thread_id },\n      };\n\n      const { checkpoint, metadata } = initialCheckpointTuple({\n        thread_id,\n        checkpoint_id: checkpoint_id1,\n        checkpoint_ns: \"\",\n      });\n\n      const returnedConfig = await checkpointer.put(\n        missingNamespaceConfig,\n        checkpoint,\n        metadata!,\n        {}\n      );\n\n      expect(returnedConfig).not.toBeUndefined();\n      expect(returnedConfig?.configurable).not.toBeUndefined();\n      expect(returnedConfig?.configurable?.checkpoint_ns).not.toBeUndefined();\n      expect(returnedConfig?.configurable?.checkpoint_ns).toEqual(\"\");\n    });\n\n    it_skipForSomeModules(initializer.checkpointerName, {\n      // TODO: all of the checkpointers below store full channel_values on every put, rather than storing deltas\n      // see: https://github.com/langchain-ai/langgraphjs/issues/593\n      // see: https://github.com/langchain-ai/langgraphjs/issues/594\n      // see: https://github.com/langchain-ai/langgraphjs/issues/595\n      MemorySaver: \"TODO: MemorySaver doesn't store channel deltas\",\n      \"@langchain/langgraph-checkpoint-mongodb\":\n        \"TODO: MongoDBSaver doesn't store channel deltas\",\n      \"@langchain/langgraph-checkpoint-sqlite\":\n        \"TODO: SQLiteSaver doesn't store channel deltas\",\n    })(\n      \"should only store channel_values that have changed (based on newVersions)\",\n      async () => {\n        const newVersions = [{}, { foo: 1 }, { foo: 1, baz: 1 }] as Record<\n          string,\n          number | string\n        >[];\n\n        const generatedPuts = newVersions.map((newVersions) => ({\n          tuple: initialCheckpointTuple({\n            thread_id,\n            checkpoint_id: uuid6(3),\n            checkpoint_ns: \"\",\n            channel_values: {\n              foo: \"bar\",\n              baz: \"qux\",\n            },\n          }),\n          writes: [],\n          newVersions,\n        }));\n\n        const storedTuples: CheckpointTuple[] = [];\n        for await (const tuple of putTuples(checkpointer, generatedPuts)) {\n          storedTuples.push(tuple);\n        }\n\n        const expectedChannelValues = [\n          {},\n          {\n            foo: \"bar\",\n          },\n          {\n            foo: \"bar\",\n            baz: \"qux\",\n          },\n        ];\n\n        expect(\n          storedTuples.map((tuple) => tuple.checkpoint.channel_values)\n        ).toEqual(expectedChannelValues);\n      }\n    );\n  });\n}\n"],"mappings":"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"}