@langchain/core 1.1.6 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/caches/index.d.ts.map +1 -1
  3. package/dist/callbacks/base.cjs.map +1 -1
  4. package/dist/callbacks/base.d.cts +2 -2
  5. package/dist/callbacks/base.d.cts.map +1 -1
  6. package/dist/callbacks/base.d.ts +2 -2
  7. package/dist/callbacks/base.d.ts.map +1 -1
  8. package/dist/callbacks/base.js.map +1 -1
  9. package/dist/callbacks/manager.cjs +3 -3
  10. package/dist/callbacks/manager.cjs.map +1 -1
  11. package/dist/callbacks/manager.d.cts +1 -1
  12. package/dist/callbacks/manager.d.cts.map +1 -1
  13. package/dist/callbacks/manager.d.ts +1 -1
  14. package/dist/callbacks/manager.d.ts.map +1 -1
  15. package/dist/callbacks/manager.js +3 -3
  16. package/dist/callbacks/manager.js.map +1 -1
  17. package/dist/language_models/chat_models.d.ts.map +1 -1
  18. package/dist/load/import_map.cjs +2 -0
  19. package/dist/load/import_map.cjs.map +1 -1
  20. package/dist/load/import_map.js +2 -0
  21. package/dist/load/import_map.js.map +1 -1
  22. package/dist/load/index.cjs +85 -25
  23. package/dist/load/index.cjs.map +1 -1
  24. package/dist/load/index.d.cts +113 -3
  25. package/dist/load/index.d.cts.map +1 -1
  26. package/dist/load/index.d.ts +113 -3
  27. package/dist/load/index.d.ts.map +1 -1
  28. package/dist/load/index.js +85 -25
  29. package/dist/load/index.js.map +1 -1
  30. package/dist/load/serializable.cjs +6 -1
  31. package/dist/load/serializable.cjs.map +1 -1
  32. package/dist/load/serializable.d.cts +15 -1
  33. package/dist/load/serializable.d.cts.map +1 -1
  34. package/dist/load/serializable.d.ts +15 -1
  35. package/dist/load/serializable.d.ts.map +1 -1
  36. package/dist/load/serializable.js +6 -1
  37. package/dist/load/serializable.js.map +1 -1
  38. package/dist/load/validation.cjs +98 -0
  39. package/dist/load/validation.cjs.map +1 -0
  40. package/dist/load/validation.js +95 -0
  41. package/dist/load/validation.js.map +1 -0
  42. package/dist/messages/base.cjs +1 -0
  43. package/dist/messages/base.cjs.map +1 -1
  44. package/dist/messages/base.d.cts +2 -3
  45. package/dist/messages/base.d.cts.map +1 -1
  46. package/dist/messages/base.d.ts +2 -3
  47. package/dist/messages/base.d.ts.map +1 -1
  48. package/dist/messages/base.js +1 -0
  49. package/dist/messages/base.js.map +1 -1
  50. package/dist/messages/message.cjs.map +1 -1
  51. package/dist/messages/message.d.cts +34 -1
  52. package/dist/messages/message.d.cts.map +1 -1
  53. package/dist/messages/message.d.ts +34 -1
  54. package/dist/messages/message.d.ts.map +1 -1
  55. package/dist/messages/message.js.map +1 -1
  56. package/dist/runnables/base.cjs +1 -1
  57. package/dist/runnables/base.cjs.map +1 -1
  58. package/dist/runnables/base.js +1 -1
  59. package/dist/runnables/base.js.map +1 -1
  60. package/dist/tracers/base.cjs +5 -2
  61. package/dist/tracers/base.cjs.map +1 -1
  62. package/dist/tracers/base.d.cts +1 -1
  63. package/dist/tracers/base.d.cts.map +1 -1
  64. package/dist/tracers/base.d.ts +1 -1
  65. package/dist/tracers/base.d.ts.map +1 -1
  66. package/dist/tracers/base.js +5 -2
  67. package/dist/tracers/base.js.map +1 -1
  68. package/dist/tracers/tracer_langchain.cjs +31 -3
  69. package/dist/tracers/tracer_langchain.cjs.map +1 -1
  70. package/dist/tracers/tracer_langchain.d.cts +8 -7
  71. package/dist/tracers/tracer_langchain.d.cts.map +1 -1
  72. package/dist/tracers/tracer_langchain.d.ts +8 -7
  73. package/dist/tracers/tracer_langchain.d.ts.map +1 -1
  74. package/dist/tracers/tracer_langchain.js +31 -3
  75. package/dist/tracers/tracer_langchain.js.map +1 -1
  76. package/dist/utils/context.cjs +107 -0
  77. package/dist/utils/context.cjs.map +1 -0
  78. package/dist/utils/context.d.cts +44 -0
  79. package/dist/utils/context.d.cts.map +1 -0
  80. package/dist/utils/context.d.ts +44 -0
  81. package/dist/utils/context.d.ts.map +1 -0
  82. package/dist/utils/context.js +101 -0
  83. package/dist/utils/context.js.map +1 -0
  84. package/dist/utils/event_source_parse.d.cts.map +1 -1
  85. package/dist/utils/stream.d.cts.map +1 -1
  86. package/dist/vectorstores.d.cts.map +1 -1
  87. package/package.json +13 -2
  88. package/utils/context.cjs +1 -0
  89. package/utils/context.d.cts +1 -0
  90. package/utils/context.d.ts +1 -0
  91. package/utils/context.js +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["constructor: typeof Serializable","aliases: { [key: string]: string }","value: unknown","getEnvironmentVariable","coreImportMap","module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null","defaultOptionalImportEntrypoints","optionalImportEntrypoints","module","finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"]","importMapKey: string","get_lc_unique_name","mapKeys","keyFromJson","value","text: string","mappings?: {\n secretsMap?: SecretMap;\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n importMap?: Record<string, unknown>;\n }"],"sources":["../../src/load/index.ts"],"sourcesContent":["import {\n Serializable,\n SerializedConstructor,\n SerializedNotImplemented,\n SerializedSecret,\n get_lc_unique_name,\n} from \"./serializable.js\";\nimport { optionalImportEntrypoints as defaultOptionalImportEntrypoints } from \"./import_constants.js\";\nimport * as coreImportMap from \"./import_map.js\";\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nimport { type SerializedFields, keyFromJson, mapKeys } from \"./map_keys.js\";\nimport { getEnvironmentVariable } from \"../utils/env.js\";\n\nfunction combineAliasesAndInvert(constructor: typeof Serializable) {\n const aliases: { [key: string]: string } = {};\n for (\n let current = constructor;\n current && current.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n Object.assign(aliases, Reflect.get(current.prototype, \"lc_aliases\"));\n }\n return Object.entries(aliases).reduce((acc, [key, value]) => {\n acc[value] = key;\n return acc;\n }, {} as Record<string, string>);\n}\n\nasync function reviver(\n this: {\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n secretsMap?: SecretMap;\n importMap?: Record<string, unknown>;\n path?: string[];\n },\n value: unknown\n): Promise<unknown> {\n const {\n optionalImportsMap = {},\n optionalImportEntrypoints = [],\n importMap = {},\n secretsMap = {},\n path = [\"$\"],\n } = this;\n const pathStr = path.join(\".\");\n if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"lc\" in value &&\n \"type\" in value &&\n \"id\" in value &&\n value.lc === 1 &&\n value.type === \"secret\"\n ) {\n const serialized = value as SerializedSecret;\n const [key] = serialized.id;\n if (key in secretsMap) {\n return secretsMap[key as keyof SecretMap];\n } else {\n const secretValueInEnv = getEnvironmentVariable(key);\n if (secretValueInEnv) {\n return secretValueInEnv;\n } else {\n throw new Error(\n `Missing key \"${key}\" for ${pathStr} in load(secretsMap={})`\n );\n }\n }\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"lc\" in value &&\n \"type\" in value &&\n \"id\" in value &&\n value.lc === 1 &&\n value.type === \"not_implemented\"\n ) {\n const serialized = value as SerializedNotImplemented;\n const str = JSON.stringify(serialized);\n throw new Error(\n `Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`\n );\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"lc\" in value &&\n \"type\" in value &&\n \"id\" in value &&\n \"kwargs\" in value &&\n value.lc === 1\n ) {\n const serialized = value as SerializedConstructor;\n const str = JSON.stringify(serialized);\n const [name, ...namespaceReverse] = serialized.id.slice().reverse();\n const namespace = namespaceReverse.reverse();\n const importMaps = { langchain_core: coreImportMap, langchain: importMap };\n\n let module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null = null;\n\n const optionalImportNamespaceAliases = [namespace.join(\"/\")];\n if (namespace[0] === \"langchain_community\") {\n optionalImportNamespaceAliases.push(\n [\"langchain\", ...namespace.slice(1)].join(\"/\")\n );\n }\n const matchingNamespaceAlias = optionalImportNamespaceAliases.find(\n (alias) => alias in optionalImportsMap\n );\n if (\n defaultOptionalImportEntrypoints\n .concat(optionalImportEntrypoints)\n .includes(namespace.join(\"/\")) ||\n matchingNamespaceAlias\n ) {\n if (matchingNamespaceAlias !== undefined) {\n module = await optionalImportsMap[\n matchingNamespaceAlias as keyof typeof optionalImportsMap\n ];\n } else {\n throw new Error(\n `Missing key \"${namespace.join(\n \"/\"\n )}\" for ${pathStr} in load(optionalImportsMap={})`\n );\n }\n } else {\n let finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"];\n // Currently, we only support langchain and langchain_core imports.\n if (namespace[0] === \"langchain\" || namespace[0] === \"langchain_core\") {\n finalImportMap = importMaps[namespace[0]];\n namespace.shift();\n } else {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // The root namespace \"langchain\" is not a valid import.\n if (namespace.length === 0) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Find the longest matching namespace.\n let importMapKey: string;\n do {\n importMapKey = namespace.join(\"__\");\n if (importMapKey in finalImportMap) {\n break;\n } else {\n namespace.pop();\n }\n } while (namespace.length > 0);\n\n // If no matching namespace is found, throw an error.\n if (importMapKey in finalImportMap) {\n module = finalImportMap[importMapKey as keyof typeof finalImportMap];\n }\n }\n\n if (typeof module !== \"object\" || module === null) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Extract the builder from the import map.\n const builder =\n // look for a named export with the same name as the class\n module[name as keyof typeof module] ??\n // look for an export with a lc_name property matching the class name\n // this is necessary for classes that are minified\n Object.values(module).find(\n (v) =>\n typeof v === \"function\" &&\n get_lc_unique_name(v as typeof Serializable) === name\n );\n if (typeof builder !== \"function\") {\n throw new Error(`Invalid identifer: ${pathStr} -> ${str}`);\n }\n\n // Recurse on the arguments, which may be serialized objects themselves\n const kwargs = await reviver.call(\n { ...this, path: [...path, \"kwargs\"] },\n serialized.kwargs\n );\n\n // Construct the object\n if (serialized.type === \"constructor\") {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const instance = new (builder as any)(\n mapKeys(\n kwargs as SerializedFields,\n keyFromJson,\n combineAliasesAndInvert(builder)\n )\n );\n\n // Minification in severless/edge runtimes will mange the\n // name of classes presented in traces. As the names in import map\n // are present as-is even with minification, use these names instead\n Object.defineProperty(instance.constructor, \"name\", { value: name });\n\n return instance;\n } else {\n throw new Error(`Invalid type: ${pathStr} -> ${str}`);\n }\n } else if (typeof value === \"object\" && value !== null) {\n if (Array.isArray(value)) {\n return Promise.all(\n value.map((v, i) =>\n reviver.call({ ...this, path: [...path, `${i}`] }, v)\n )\n );\n } else {\n return Object.fromEntries(\n await Promise.all(\n Object.entries(value).map(async ([key, value]) => [\n key,\n await reviver.call({ ...this, path: [...path, key] }, value),\n ])\n )\n );\n }\n }\n return value;\n}\n\nexport async function load<T>(\n text: string,\n mappings?: {\n secretsMap?: SecretMap;\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n importMap?: Record<string, unknown>;\n }\n): Promise<T> {\n const json = JSON.parse(text);\n return reviver.call({ ...mappings }, json) as Promise<T>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["constructor: typeof Serializable","aliases: { [key: string]: string }","value: unknown","isEscapedObject","unescapeValue","getEnvironmentVariable","coreImportMap","module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null","defaultOptionalImportEntrypoints","optionalImportEntrypoints","module","finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"]","importMapKey: string","get_lc_unique_name","mapKeys","keyFromJson","result: Record<string, unknown>","text: string","options?: LoadOptions","context: ReviverContext"],"sources":["../../src/load/index.ts"],"sourcesContent":["/**\n * Load LangChain objects from JSON strings or objects.\n *\n * ## How it works\n *\n * Each `Serializable` LangChain object has a unique identifier (its \"class path\"),\n * which is a list of strings representing the module path and class name. For example:\n *\n * - `AIMessage` -> `[\"langchain_core\", \"messages\", \"ai\", \"AIMessage\"]`\n * - `ChatPromptTemplate` -> `[\"langchain_core\", \"prompts\", \"chat\", \"ChatPromptTemplate\"]`\n *\n * When deserializing, the class path is validated against supported namespaces.\n *\n * ## Security model\n *\n * The `secretsFromEnv` parameter controls whether secrets can be loaded from environment\n * variables:\n *\n * - `false` (default): Secrets must be provided in `secretsMap`. If a secret is not\n * found, `null` is returned instead of loading from environment variables.\n * - `true`: If a secret is not found in `secretsMap`, it will be loaded from\n * environment variables. Use this only in trusted environments.\n *\n * ### Injection protection (escape-based)\n *\n * During serialization, plain objects that contain an `'lc'` key are escaped by wrapping\n * them: `{\"__lc_escaped__\": {...}}`. During deserialization, escaped objects are unwrapped\n * and returned as plain objects, NOT instantiated as LC objects.\n *\n * This is an allowlist approach: only objects explicitly produced by\n * `Serializable.toJSON()` (which are NOT escaped) are treated as LC objects;\n * everything else is user data.\n *\n * @module\n */\n\nimport {\n Serializable,\n SerializedConstructor,\n SerializedNotImplemented,\n SerializedSecret,\n get_lc_unique_name,\n} from \"./serializable.js\";\nimport { optionalImportEntrypoints as defaultOptionalImportEntrypoints } from \"./import_constants.js\";\nimport * as coreImportMap from \"./import_map.js\";\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nimport { type SerializedFields, keyFromJson, mapKeys } from \"./map_keys.js\";\nimport { getEnvironmentVariable } from \"../utils/env.js\";\nimport { isEscapedObject, unescapeValue } from \"./validation.js\";\n\n/**\n * Options for loading serialized LangChain objects.\n *\n * @remarks\n * **Security considerations:**\n *\n * Deserialization can instantiate arbitrary classes from the allowed namespaces.\n * When loading untrusted data, be aware that:\n *\n * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the\n * deserializer to read environment variables, which could leak secrets if\n * the serialized data contains malicious secret references.\n *\n * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes\n * can be instantiated. Never populate these from user input. Only include\n * modules you explicitly trust.\n *\n * 3. **Class instantiation**: Allowed classes will have their constructors called\n * with the deserialized kwargs. If a class performs side effects in its\n * constructor (network calls, file I/O, etc.), those will execute.\n */\nexport interface LoadOptions {\n /**\n * A map of secrets to load. Keys are secret identifiers, values are the secret values.\n *\n * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is\n * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment\n * variables (if not found there either, an error is thrown).\n */\n secretsMap?: SecretMap;\n\n /**\n * Whether to load secrets from environment variables when not found in `secretsMap`.\n *\n * @default false\n *\n * @remarks\n * **Security warning:** Setting this to `true` allows the deserializer to read\n * environment variables, which could be a security risk if the serialized data\n * is not trusted. Only set this to `true` when deserializing data from trusted\n * sources (e.g., your own database, not user input).\n */\n secretsFromEnv?: boolean;\n\n /**\n * A map of optional imports. Keys are namespace paths (e.g., \"langchain_community/llms\"),\n * values are the imported modules.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Classes in these modules can be instantiated with attacker-controlled kwargs\n * if the serialized data is untrusted.\n */\n optionalImportsMap?: OptionalImportMap;\n\n /**\n * Additional optional import entrypoints to allow beyond the defaults.\n *\n * @remarks\n * **Security warning:** This extends which namespace paths are considered valid\n * for deserialization. Never populate this array with values derived from user\n * input. Each entrypoint you add expands the attack surface for deserialization.\n */\n optionalImportEntrypoints?: string[];\n\n /**\n * Additional import map for the \"langchain\" namespace.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Any class exposed through this map can be instantiated with attacker-controlled\n * kwargs if the serialized data is untrusted.\n */\n importMap?: Record<string, unknown>;\n\n /**\n * Maximum recursion depth allowed during deserialization.\n *\n * @default 50\n *\n * @remarks\n * This limit protects against denial-of-service attacks using deeply nested\n * JSON structures that could cause stack overflow. If your legitimate data\n * requires deeper nesting, you can increase this limit.\n */\n maxDepth?: number;\n}\n\n/**\n * Default maximum recursion depth for deserialization.\n * This provides protection against DoS attacks via deeply nested structures.\n */\nconst DEFAULT_MAX_DEPTH = 50;\n\nfunction combineAliasesAndInvert(constructor: typeof Serializable) {\n const aliases: { [key: string]: string } = {};\n for (\n let current = constructor;\n current && current.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n Object.assign(aliases, Reflect.get(current.prototype, \"lc_aliases\"));\n }\n return Object.entries(aliases).reduce((acc, [key, value]) => {\n acc[value] = key;\n return acc;\n }, {} as Record<string, string>);\n}\n\ninterface ReviverContext {\n optionalImportsMap: OptionalImportMap;\n optionalImportEntrypoints: string[];\n secretsMap: SecretMap;\n secretsFromEnv: boolean;\n importMap: Record<string, unknown>;\n path: string[];\n depth: number;\n maxDepth: number;\n}\n\n/**\n * Recursively revive a value, handling escape markers and LC objects.\n *\n * This function handles:\n * 1. Escaped dicts - unwrapped and returned as plain objects\n * 2. LC secret objects - resolved from secretsMap or env\n * 3. LC constructor objects - instantiated\n * 4. Regular objects/arrays - recursed into\n */\nasync function reviver(this: ReviverContext, value: unknown): Promise<unknown> {\n const {\n optionalImportsMap,\n optionalImportEntrypoints,\n importMap,\n secretsMap,\n secretsFromEnv,\n path,\n depth,\n maxDepth,\n } = this;\n const pathStr = path.join(\".\");\n\n // Check recursion depth to prevent DoS via deeply nested structures\n if (depth > maxDepth) {\n throw new Error(\n `Maximum recursion depth (${maxDepth}) exceeded during deserialization. ` +\n `This may indicate a malicious payload or you may need to increase maxDepth.`\n );\n }\n\n // If not an object, return as-is\n if (typeof value !== \"object\" || value == null) {\n return value;\n }\n\n // Handle arrays - recurse into elements\n if (Array.isArray(value)) {\n return Promise.all(\n value.map((v, i) =>\n reviver.call({ ...this, path: [...path, `${i}`], depth: depth + 1 }, v)\n )\n );\n }\n\n // It's an object - check for escape marker FIRST\n const record = value as Record<string, unknown>;\n if (isEscapedObject(record)) {\n // This is an escaped user object - unwrap and return as-is (no LC processing)\n return unescapeValue(record);\n }\n\n // Check for LC secret object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"secret\"\n ) {\n const serialized = record as unknown as SerializedSecret;\n const [key] = serialized.id;\n if (key in secretsMap) {\n return secretsMap[key as keyof SecretMap];\n } else if (secretsFromEnv) {\n const secretValueInEnv = getEnvironmentVariable(key);\n if (secretValueInEnv) {\n return secretValueInEnv;\n }\n }\n throw new Error(`Missing secret \"${key}\" at ${pathStr}`);\n }\n\n // Check for LC not_implemented object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"not_implemented\"\n ) {\n const serialized = record as unknown as SerializedNotImplemented;\n const str = JSON.stringify(serialized);\n throw new Error(\n `Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`\n );\n }\n\n // Check for LC constructor object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n \"kwargs\" in record &&\n record.lc === 1 &&\n record.type === \"constructor\"\n ) {\n const serialized = record as unknown as SerializedConstructor;\n const str = JSON.stringify(serialized);\n const [name, ...namespaceReverse] = serialized.id.slice().reverse();\n const namespace = namespaceReverse.reverse();\n const importMaps = { langchain_core: coreImportMap, langchain: importMap };\n\n let module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null = null;\n\n const optionalImportNamespaceAliases = [namespace.join(\"/\")];\n if (namespace[0] === \"langchain_community\") {\n optionalImportNamespaceAliases.push(\n [\"langchain\", ...namespace.slice(1)].join(\"/\")\n );\n }\n const matchingNamespaceAlias = optionalImportNamespaceAliases.find(\n (alias) => alias in optionalImportsMap\n );\n if (\n defaultOptionalImportEntrypoints\n .concat(optionalImportEntrypoints)\n .includes(namespace.join(\"/\")) ||\n matchingNamespaceAlias\n ) {\n if (matchingNamespaceAlias !== undefined) {\n module = await optionalImportsMap[\n matchingNamespaceAlias as keyof typeof optionalImportsMap\n ];\n } else {\n throw new Error(\n `Missing key \"${namespace.join(\n \"/\"\n )}\" for ${pathStr} in load(optionalImportsMap={})`\n );\n }\n } else {\n let finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"];\n // Currently, we only support langchain and langchain_core imports.\n if (namespace[0] === \"langchain\" || namespace[0] === \"langchain_core\") {\n finalImportMap = importMaps[namespace[0]];\n namespace.shift();\n } else {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // The root namespace \"langchain\" is not a valid import.\n if (namespace.length === 0) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Find the longest matching namespace.\n let importMapKey: string;\n do {\n importMapKey = namespace.join(\"__\");\n if (importMapKey in finalImportMap) {\n break;\n } else {\n namespace.pop();\n }\n } while (namespace.length > 0);\n\n // If no matching namespace is found, throw an error.\n if (importMapKey in finalImportMap) {\n module = finalImportMap[importMapKey as keyof typeof finalImportMap];\n }\n }\n\n if (typeof module !== \"object\" || module === null) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Extract the builder from the import map.\n const builder =\n // look for a named export with the same name as the class\n module[name as keyof typeof module] ??\n // look for an export with a lc_name property matching the class name\n // this is necessary for classes that are minified\n Object.values(module).find(\n (v) =>\n typeof v === \"function\" &&\n get_lc_unique_name(v as typeof Serializable) === name\n );\n if (typeof builder !== \"function\") {\n throw new Error(`Invalid identifer: ${pathStr} -> ${str}`);\n }\n\n // Recurse on the arguments, which may be serialized objects themselves\n const kwargs = await reviver.call(\n { ...this, path: [...path, \"kwargs\"], depth: depth + 1 },\n serialized.kwargs\n );\n\n // Construct the object\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const instance = new (builder as any)(\n mapKeys(\n kwargs as SerializedFields,\n keyFromJson,\n combineAliasesAndInvert(builder)\n )\n );\n\n // Minification in severless/edge runtimes will mange the\n // name of classes presented in traces. As the names in import map\n // are present as-is even with minification, use these names instead\n Object.defineProperty(instance.constructor, \"name\", { value: name });\n\n return instance;\n }\n\n // Regular object - recurse into values\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n result[key] = await reviver.call(\n { ...this, path: [...path, key], depth: depth + 1 },\n val\n );\n }\n return result;\n}\n\n/**\n * Load a LangChain object from a JSON string.\n *\n * @param text - The JSON string to parse and load.\n * @param options - Options for loading.\n * @returns The loaded LangChain object.\n *\n * @example\n * ```typescript\n * import { load } from \"@langchain/core/load\";\n * import { AIMessage } from \"@langchain/core/messages\";\n *\n * // Basic usage - secrets must be provided explicitly\n * const msg = await load<AIMessage>(jsonString);\n *\n * // With secrets from a map\n * const msg = await load<AIMessage>(jsonString, {\n * secretsMap: { OPENAI_API_KEY: \"sk-...\" }\n * });\n *\n * // Allow loading secrets from environment (use with caution)\n * const msg = await load<AIMessage>(jsonString, {\n * secretsFromEnv: true\n * });\n * ```\n */\nexport async function load<T>(text: string, options?: LoadOptions): Promise<T> {\n const json = JSON.parse(text);\n\n const context: ReviverContext = {\n optionalImportsMap: options?.optionalImportsMap ?? {},\n optionalImportEntrypoints: options?.optionalImportEntrypoints ?? [],\n secretsMap: options?.secretsMap ?? {},\n secretsFromEnv: options?.secretsFromEnv ?? false,\n importMap: options?.importMap ?? {},\n path: [\"$\"],\n depth: 0,\n maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n };\n\n return reviver.call(context, json) as Promise<T>;\n}\n"],"mappings":"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"}
@@ -1,12 +1,122 @@
1
1
  import { OptionalImportMap, SecretMap } from "./import_type.cjs";
2
2
 
3
3
  //#region src/load/index.d.ts
4
- declare function load<T>(text: string, mappings?: {
4
+
5
+ /**
6
+ * Options for loading serialized LangChain objects.
7
+ *
8
+ * @remarks
9
+ * **Security considerations:**
10
+ *
11
+ * Deserialization can instantiate arbitrary classes from the allowed namespaces.
12
+ * When loading untrusted data, be aware that:
13
+ *
14
+ * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the
15
+ * deserializer to read environment variables, which could leak secrets if
16
+ * the serialized data contains malicious secret references.
17
+ *
18
+ * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes
19
+ * can be instantiated. Never populate these from user input. Only include
20
+ * modules you explicitly trust.
21
+ *
22
+ * 3. **Class instantiation**: Allowed classes will have their constructors called
23
+ * with the deserialized kwargs. If a class performs side effects in its
24
+ * constructor (network calls, file I/O, etc.), those will execute.
25
+ */
26
+ interface LoadOptions {
27
+ /**
28
+ * A map of secrets to load. Keys are secret identifiers, values are the secret values.
29
+ *
30
+ * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is
31
+ * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment
32
+ * variables (if not found there either, an error is thrown).
33
+ */
5
34
  secretsMap?: SecretMap;
35
+ /**
36
+ * Whether to load secrets from environment variables when not found in `secretsMap`.
37
+ *
38
+ * @default false
39
+ *
40
+ * @remarks
41
+ * **Security warning:** Setting this to `true` allows the deserializer to read
42
+ * environment variables, which could be a security risk if the serialized data
43
+ * is not trusted. Only set this to `true` when deserializing data from trusted
44
+ * sources (e.g., your own database, not user input).
45
+ */
46
+ secretsFromEnv?: boolean;
47
+ /**
48
+ * A map of optional imports. Keys are namespace paths (e.g., "langchain_community/llms"),
49
+ * values are the imported modules.
50
+ *
51
+ * @remarks
52
+ * **Security warning:** This extends which classes can be instantiated during
53
+ * deserialization. Never populate this map with values derived from user input.
54
+ * Only include modules that you explicitly trust and have reviewed.
55
+ *
56
+ * Classes in these modules can be instantiated with attacker-controlled kwargs
57
+ * if the serialized data is untrusted.
58
+ */
6
59
  optionalImportsMap?: OptionalImportMap;
60
+ /**
61
+ * Additional optional import entrypoints to allow beyond the defaults.
62
+ *
63
+ * @remarks
64
+ * **Security warning:** This extends which namespace paths are considered valid
65
+ * for deserialization. Never populate this array with values derived from user
66
+ * input. Each entrypoint you add expands the attack surface for deserialization.
67
+ */
7
68
  optionalImportEntrypoints?: string[];
69
+ /**
70
+ * Additional import map for the "langchain" namespace.
71
+ *
72
+ * @remarks
73
+ * **Security warning:** This extends which classes can be instantiated during
74
+ * deserialization. Never populate this map with values derived from user input.
75
+ * Only include modules that you explicitly trust and have reviewed.
76
+ *
77
+ * Any class exposed through this map can be instantiated with attacker-controlled
78
+ * kwargs if the serialized data is untrusted.
79
+ */
8
80
  importMap?: Record<string, unknown>;
9
- }): Promise<T>;
81
+ /**
82
+ * Maximum recursion depth allowed during deserialization.
83
+ *
84
+ * @default 50
85
+ *
86
+ * @remarks
87
+ * This limit protects against denial-of-service attacks using deeply nested
88
+ * JSON structures that could cause stack overflow. If your legitimate data
89
+ * requires deeper nesting, you can increase this limit.
90
+ */
91
+ maxDepth?: number;
92
+ }
93
+ /**
94
+ * Load a LangChain object from a JSON string.
95
+ *
96
+ * @param text - The JSON string to parse and load.
97
+ * @param options - Options for loading.
98
+ * @returns The loaded LangChain object.
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * import { load } from "@langchain/core/load";
103
+ * import { AIMessage } from "@langchain/core/messages";
104
+ *
105
+ * // Basic usage - secrets must be provided explicitly
106
+ * const msg = await load<AIMessage>(jsonString);
107
+ *
108
+ * // With secrets from a map
109
+ * const msg = await load<AIMessage>(jsonString, {
110
+ * secretsMap: { OPENAI_API_KEY: "sk-..." }
111
+ * });
112
+ *
113
+ * // Allow loading secrets from environment (use with caution)
114
+ * const msg = await load<AIMessage>(jsonString, {
115
+ * secretsFromEnv: true
116
+ * });
117
+ * ```
118
+ */
119
+ declare function load<T>(text: string, options?: LoadOptions): Promise<T>;
10
120
  //#endregion
11
- export { load };
121
+ export { LoadOptions, load };
12
122
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":["OptionalImportMap","SecretMap","load","T","Record","Promise"],"sources":["../../src/load/index.d.ts"],"sourcesContent":["import type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nexport declare function load<T>(text: string, mappings?: {\n secretsMap?: SecretMap;\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n importMap?: Record<string, unknown>;\n}): Promise<T>;\n//# sourceMappingURL=index.d.ts.map"],"mappings":";;;iBACwBE,8BAIRE;eAHCH;EADOC,kBAAIC,CAAAA,EAEHH,iBAFG;EACXC,yBAAAA,CAAAA,EAAAA,MAAAA,EAAAA;EACQD,SAAAA,CAAAA,EAETI,MAFSJ,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA;CAETI,CAAAA,EACZC,OADYD,CACJD,CADIC,CAAAA"}
1
+ {"version":3,"file":"index.d.cts","names":["OptionalImportMap","SecretMap","LoadOptions","Record","load","T","Promise"],"sources":["../../src/load/index.d.ts"],"sourcesContent":["/**\n * Load LangChain objects from JSON strings or objects.\n *\n * ## How it works\n *\n * Each `Serializable` LangChain object has a unique identifier (its \"class path\"),\n * which is a list of strings representing the module path and class name. For example:\n *\n * - `AIMessage` -> `[\"langchain_core\", \"messages\", \"ai\", \"AIMessage\"]`\n * - `ChatPromptTemplate` -> `[\"langchain_core\", \"prompts\", \"chat\", \"ChatPromptTemplate\"]`\n *\n * When deserializing, the class path is validated against supported namespaces.\n *\n * ## Security model\n *\n * The `secretsFromEnv` parameter controls whether secrets can be loaded from environment\n * variables:\n *\n * - `false` (default): Secrets must be provided in `secretsMap`. If a secret is not\n * found, `null` is returned instead of loading from environment variables.\n * - `true`: If a secret is not found in `secretsMap`, it will be loaded from\n * environment variables. Use this only in trusted environments.\n *\n * ### Injection protection (escape-based)\n *\n * During serialization, plain objects that contain an `'lc'` key are escaped by wrapping\n * them: `{\"__lc_escaped__\": {...}}`. During deserialization, escaped objects are unwrapped\n * and returned as plain objects, NOT instantiated as LC objects.\n *\n * This is an allowlist approach: only objects explicitly produced by\n * `Serializable.toJSON()` (which are NOT escaped) are treated as LC objects;\n * everything else is user data.\n *\n * @module\n */\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\n/**\n * Options for loading serialized LangChain objects.\n *\n * @remarks\n * **Security considerations:**\n *\n * Deserialization can instantiate arbitrary classes from the allowed namespaces.\n * When loading untrusted data, be aware that:\n *\n * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the\n * deserializer to read environment variables, which could leak secrets if\n * the serialized data contains malicious secret references.\n *\n * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes\n * can be instantiated. Never populate these from user input. Only include\n * modules you explicitly trust.\n *\n * 3. **Class instantiation**: Allowed classes will have their constructors called\n * with the deserialized kwargs. If a class performs side effects in its\n * constructor (network calls, file I/O, etc.), those will execute.\n */\nexport interface LoadOptions {\n /**\n * A map of secrets to load. Keys are secret identifiers, values are the secret values.\n *\n * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is\n * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment\n * variables (if not found there either, an error is thrown).\n */\n secretsMap?: SecretMap;\n /**\n * Whether to load secrets from environment variables when not found in `secretsMap`.\n *\n * @default false\n *\n * @remarks\n * **Security warning:** Setting this to `true` allows the deserializer to read\n * environment variables, which could be a security risk if the serialized data\n * is not trusted. Only set this to `true` when deserializing data from trusted\n * sources (e.g., your own database, not user input).\n */\n secretsFromEnv?: boolean;\n /**\n * A map of optional imports. Keys are namespace paths (e.g., \"langchain_community/llms\"),\n * values are the imported modules.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Classes in these modules can be instantiated with attacker-controlled kwargs\n * if the serialized data is untrusted.\n */\n optionalImportsMap?: OptionalImportMap;\n /**\n * Additional optional import entrypoints to allow beyond the defaults.\n *\n * @remarks\n * **Security warning:** This extends which namespace paths are considered valid\n * for deserialization. Never populate this array with values derived from user\n * input. Each entrypoint you add expands the attack surface for deserialization.\n */\n optionalImportEntrypoints?: string[];\n /**\n * Additional import map for the \"langchain\" namespace.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Any class exposed through this map can be instantiated with attacker-controlled\n * kwargs if the serialized data is untrusted.\n */\n importMap?: Record<string, unknown>;\n /**\n * Maximum recursion depth allowed during deserialization.\n *\n * @default 50\n *\n * @remarks\n * This limit protects against denial-of-service attacks using deeply nested\n * JSON structures that could cause stack overflow. If your legitimate data\n * requires deeper nesting, you can increase this limit.\n */\n maxDepth?: number;\n}\n/**\n * Load a LangChain object from a JSON string.\n *\n * @param text - The JSON string to parse and load.\n * @param options - Options for loading.\n * @returns The loaded LangChain object.\n *\n * @example\n * ```typescript\n * import { load } from \"@langchain/core/load\";\n * import { AIMessage } from \"@langchain/core/messages\";\n *\n * // Basic usage - secrets must be provided explicitly\n * const msg = await load<AIMessage>(jsonString);\n *\n * // With secrets from a map\n * const msg = await load<AIMessage>(jsonString, {\n * secretsMap: { OPENAI_API_KEY: \"sk-...\" }\n * });\n *\n * // Allow loading secrets from environment (use with caution)\n * const msg = await load<AIMessage>(jsonString, {\n * secretsFromEnv: true\n * });\n * ```\n */\nexport declare function load<T>(text: string, options?: LoadOptions): Promise<T>;\n//# sourceMappingURL=index.d.ts.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;UAyDiBE,WAAAA;;;;;;;;eAQAD;;;;;;;;;;;;;;;;;;;;;;;;;uBAyBQD;;;;;;;;;;;;;;;;;;;;;cAqBTG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuCQC,gCAAgCF,cAAcI,QAAQD"}
@@ -1,12 +1,122 @@
1
1
  import { OptionalImportMap, SecretMap } from "./import_type.js";
2
2
 
3
3
  //#region src/load/index.d.ts
4
- declare function load<T>(text: string, mappings?: {
4
+
5
+ /**
6
+ * Options for loading serialized LangChain objects.
7
+ *
8
+ * @remarks
9
+ * **Security considerations:**
10
+ *
11
+ * Deserialization can instantiate arbitrary classes from the allowed namespaces.
12
+ * When loading untrusted data, be aware that:
13
+ *
14
+ * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the
15
+ * deserializer to read environment variables, which could leak secrets if
16
+ * the serialized data contains malicious secret references.
17
+ *
18
+ * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes
19
+ * can be instantiated. Never populate these from user input. Only include
20
+ * modules you explicitly trust.
21
+ *
22
+ * 3. **Class instantiation**: Allowed classes will have their constructors called
23
+ * with the deserialized kwargs. If a class performs side effects in its
24
+ * constructor (network calls, file I/O, etc.), those will execute.
25
+ */
26
+ interface LoadOptions {
27
+ /**
28
+ * A map of secrets to load. Keys are secret identifiers, values are the secret values.
29
+ *
30
+ * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is
31
+ * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment
32
+ * variables (if not found there either, an error is thrown).
33
+ */
5
34
  secretsMap?: SecretMap;
35
+ /**
36
+ * Whether to load secrets from environment variables when not found in `secretsMap`.
37
+ *
38
+ * @default false
39
+ *
40
+ * @remarks
41
+ * **Security warning:** Setting this to `true` allows the deserializer to read
42
+ * environment variables, which could be a security risk if the serialized data
43
+ * is not trusted. Only set this to `true` when deserializing data from trusted
44
+ * sources (e.g., your own database, not user input).
45
+ */
46
+ secretsFromEnv?: boolean;
47
+ /**
48
+ * A map of optional imports. Keys are namespace paths (e.g., "langchain_community/llms"),
49
+ * values are the imported modules.
50
+ *
51
+ * @remarks
52
+ * **Security warning:** This extends which classes can be instantiated during
53
+ * deserialization. Never populate this map with values derived from user input.
54
+ * Only include modules that you explicitly trust and have reviewed.
55
+ *
56
+ * Classes in these modules can be instantiated with attacker-controlled kwargs
57
+ * if the serialized data is untrusted.
58
+ */
6
59
  optionalImportsMap?: OptionalImportMap;
60
+ /**
61
+ * Additional optional import entrypoints to allow beyond the defaults.
62
+ *
63
+ * @remarks
64
+ * **Security warning:** This extends which namespace paths are considered valid
65
+ * for deserialization. Never populate this array with values derived from user
66
+ * input. Each entrypoint you add expands the attack surface for deserialization.
67
+ */
7
68
  optionalImportEntrypoints?: string[];
69
+ /**
70
+ * Additional import map for the "langchain" namespace.
71
+ *
72
+ * @remarks
73
+ * **Security warning:** This extends which classes can be instantiated during
74
+ * deserialization. Never populate this map with values derived from user input.
75
+ * Only include modules that you explicitly trust and have reviewed.
76
+ *
77
+ * Any class exposed through this map can be instantiated with attacker-controlled
78
+ * kwargs if the serialized data is untrusted.
79
+ */
8
80
  importMap?: Record<string, unknown>;
9
- }): Promise<T>;
81
+ /**
82
+ * Maximum recursion depth allowed during deserialization.
83
+ *
84
+ * @default 50
85
+ *
86
+ * @remarks
87
+ * This limit protects against denial-of-service attacks using deeply nested
88
+ * JSON structures that could cause stack overflow. If your legitimate data
89
+ * requires deeper nesting, you can increase this limit.
90
+ */
91
+ maxDepth?: number;
92
+ }
93
+ /**
94
+ * Load a LangChain object from a JSON string.
95
+ *
96
+ * @param text - The JSON string to parse and load.
97
+ * @param options - Options for loading.
98
+ * @returns The loaded LangChain object.
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * import { load } from "@langchain/core/load";
103
+ * import { AIMessage } from "@langchain/core/messages";
104
+ *
105
+ * // Basic usage - secrets must be provided explicitly
106
+ * const msg = await load<AIMessage>(jsonString);
107
+ *
108
+ * // With secrets from a map
109
+ * const msg = await load<AIMessage>(jsonString, {
110
+ * secretsMap: { OPENAI_API_KEY: "sk-..." }
111
+ * });
112
+ *
113
+ * // Allow loading secrets from environment (use with caution)
114
+ * const msg = await load<AIMessage>(jsonString, {
115
+ * secretsFromEnv: true
116
+ * });
117
+ * ```
118
+ */
119
+ declare function load<T>(text: string, options?: LoadOptions): Promise<T>;
10
120
  //#endregion
11
- export { load };
121
+ export { LoadOptions, load };
12
122
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["OptionalImportMap","SecretMap","load","T","Record","Promise"],"sources":["../../src/load/index.d.ts"],"sourcesContent":["import type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nexport declare function load<T>(text: string, mappings?: {\n secretsMap?: SecretMap;\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n importMap?: Record<string, unknown>;\n}): Promise<T>;\n//# sourceMappingURL=index.d.ts.map"],"mappings":";;;iBACwBE,8BAIRE;eAHCH;EADOC,kBAAIC,CAAAA,EAEHH,iBAFG;EACXC,yBAAAA,CAAAA,EAAAA,MAAAA,EAAAA;EACQD,SAAAA,CAAAA,EAETI,MAFSJ,CAAAA,MAAAA,EAAAA,OAAAA,CAAAA;CAETI,CAAAA,EACZC,OADYD,CACJD,CADIC,CAAAA"}
1
+ {"version":3,"file":"index.d.ts","names":["OptionalImportMap","SecretMap","LoadOptions","Record","load","T","Promise"],"sources":["../../src/load/index.d.ts"],"sourcesContent":["/**\n * Load LangChain objects from JSON strings or objects.\n *\n * ## How it works\n *\n * Each `Serializable` LangChain object has a unique identifier (its \"class path\"),\n * which is a list of strings representing the module path and class name. For example:\n *\n * - `AIMessage` -> `[\"langchain_core\", \"messages\", \"ai\", \"AIMessage\"]`\n * - `ChatPromptTemplate` -> `[\"langchain_core\", \"prompts\", \"chat\", \"ChatPromptTemplate\"]`\n *\n * When deserializing, the class path is validated against supported namespaces.\n *\n * ## Security model\n *\n * The `secretsFromEnv` parameter controls whether secrets can be loaded from environment\n * variables:\n *\n * - `false` (default): Secrets must be provided in `secretsMap`. If a secret is not\n * found, `null` is returned instead of loading from environment variables.\n * - `true`: If a secret is not found in `secretsMap`, it will be loaded from\n * environment variables. Use this only in trusted environments.\n *\n * ### Injection protection (escape-based)\n *\n * During serialization, plain objects that contain an `'lc'` key are escaped by wrapping\n * them: `{\"__lc_escaped__\": {...}}`. During deserialization, escaped objects are unwrapped\n * and returned as plain objects, NOT instantiated as LC objects.\n *\n * This is an allowlist approach: only objects explicitly produced by\n * `Serializable.toJSON()` (which are NOT escaped) are treated as LC objects;\n * everything else is user data.\n *\n * @module\n */\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\n/**\n * Options for loading serialized LangChain objects.\n *\n * @remarks\n * **Security considerations:**\n *\n * Deserialization can instantiate arbitrary classes from the allowed namespaces.\n * When loading untrusted data, be aware that:\n *\n * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the\n * deserializer to read environment variables, which could leak secrets if\n * the serialized data contains malicious secret references.\n *\n * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes\n * can be instantiated. Never populate these from user input. Only include\n * modules you explicitly trust.\n *\n * 3. **Class instantiation**: Allowed classes will have their constructors called\n * with the deserialized kwargs. If a class performs side effects in its\n * constructor (network calls, file I/O, etc.), those will execute.\n */\nexport interface LoadOptions {\n /**\n * A map of secrets to load. Keys are secret identifiers, values are the secret values.\n *\n * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is\n * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment\n * variables (if not found there either, an error is thrown).\n */\n secretsMap?: SecretMap;\n /**\n * Whether to load secrets from environment variables when not found in `secretsMap`.\n *\n * @default false\n *\n * @remarks\n * **Security warning:** Setting this to `true` allows the deserializer to read\n * environment variables, which could be a security risk if the serialized data\n * is not trusted. Only set this to `true` when deserializing data from trusted\n * sources (e.g., your own database, not user input).\n */\n secretsFromEnv?: boolean;\n /**\n * A map of optional imports. Keys are namespace paths (e.g., \"langchain_community/llms\"),\n * values are the imported modules.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Classes in these modules can be instantiated with attacker-controlled kwargs\n * if the serialized data is untrusted.\n */\n optionalImportsMap?: OptionalImportMap;\n /**\n * Additional optional import entrypoints to allow beyond the defaults.\n *\n * @remarks\n * **Security warning:** This extends which namespace paths are considered valid\n * for deserialization. Never populate this array with values derived from user\n * input. Each entrypoint you add expands the attack surface for deserialization.\n */\n optionalImportEntrypoints?: string[];\n /**\n * Additional import map for the \"langchain\" namespace.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Any class exposed through this map can be instantiated with attacker-controlled\n * kwargs if the serialized data is untrusted.\n */\n importMap?: Record<string, unknown>;\n /**\n * Maximum recursion depth allowed during deserialization.\n *\n * @default 50\n *\n * @remarks\n * This limit protects against denial-of-service attacks using deeply nested\n * JSON structures that could cause stack overflow. If your legitimate data\n * requires deeper nesting, you can increase this limit.\n */\n maxDepth?: number;\n}\n/**\n * Load a LangChain object from a JSON string.\n *\n * @param text - The JSON string to parse and load.\n * @param options - Options for loading.\n * @returns The loaded LangChain object.\n *\n * @example\n * ```typescript\n * import { load } from \"@langchain/core/load\";\n * import { AIMessage } from \"@langchain/core/messages\";\n *\n * // Basic usage - secrets must be provided explicitly\n * const msg = await load<AIMessage>(jsonString);\n *\n * // With secrets from a map\n * const msg = await load<AIMessage>(jsonString, {\n * secretsMap: { OPENAI_API_KEY: \"sk-...\" }\n * });\n *\n * // Allow loading secrets from environment (use with caution)\n * const msg = await load<AIMessage>(jsonString, {\n * secretsFromEnv: true\n * });\n * ```\n */\nexport declare function load<T>(text: string, options?: LoadOptions): Promise<T>;\n//# sourceMappingURL=index.d.ts.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;UAyDiBE,WAAAA;;;;;;;;eAQAD;;;;;;;;;;;;;;;;;;;;;;;;;uBAyBQD;;;;;;;;;;;;;;;;;;;;;cAqBTG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuCQC,gCAAgCF,cAAcI,QAAQD"}
@@ -1,10 +1,16 @@
1
1
  import { keyFromJson, mapKeys } from "./map_keys.js";
2
+ import { isEscapedObject, unescapeValue } from "./validation.js";
2
3
  import { get_lc_unique_name } from "./serializable.js";
3
4
  import { getEnvironmentVariable } from "../utils/env.js";
4
5
  import { optionalImportEntrypoints } from "./import_constants.js";
5
6
  import { import_map_exports } from "./import_map.js";
6
7
 
7
8
  //#region src/load/index.ts
9
+ /**
10
+ * Default maximum recursion depth for deserialization.
11
+ * This provides protection against DoS attacks via deeply nested structures.
12
+ */
13
+ const DEFAULT_MAX_DEPTH = 50;
8
14
  function combineAliasesAndInvert(constructor) {
9
15
  const aliases = {};
10
16
  for (let current = constructor; current && current.prototype; current = Object.getPrototypeOf(current)) Object.assign(aliases, Reflect.get(current.prototype, "lc_aliases"));
@@ -13,24 +19,44 @@ function combineAliasesAndInvert(constructor) {
13
19
  return acc;
14
20
  }, {});
15
21
  }
22
+ /**
23
+ * Recursively revive a value, handling escape markers and LC objects.
24
+ *
25
+ * This function handles:
26
+ * 1. Escaped dicts - unwrapped and returned as plain objects
27
+ * 2. LC secret objects - resolved from secretsMap or env
28
+ * 3. LC constructor objects - instantiated
29
+ * 4. Regular objects/arrays - recursed into
30
+ */
16
31
  async function reviver(value) {
17
- const { optionalImportsMap = {}, optionalImportEntrypoints: optionalImportEntrypoints$1 = [], importMap = {}, secretsMap = {}, path = ["$"] } = this;
32
+ const { optionalImportsMap, optionalImportEntrypoints: optionalImportEntrypoints$1, importMap, secretsMap, secretsFromEnv, path, depth, maxDepth } = this;
18
33
  const pathStr = path.join(".");
19
- if (typeof value === "object" && value !== null && !Array.isArray(value) && "lc" in value && "type" in value && "id" in value && value.lc === 1 && value.type === "secret") {
20
- const serialized = value;
34
+ if (depth > maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded during deserialization. This may indicate a malicious payload or you may need to increase maxDepth.`);
35
+ if (typeof value !== "object" || value == null) return value;
36
+ if (Array.isArray(value)) return Promise.all(value.map((v, i) => reviver.call({
37
+ ...this,
38
+ path: [...path, `${i}`],
39
+ depth: depth + 1
40
+ }, v)));
41
+ const record = value;
42
+ if (isEscapedObject(record)) return unescapeValue(record);
43
+ if ("lc" in record && "type" in record && "id" in record && record.lc === 1 && record.type === "secret") {
44
+ const serialized = record;
21
45
  const [key] = serialized.id;
22
46
  if (key in secretsMap) return secretsMap[key];
23
- else {
47
+ else if (secretsFromEnv) {
24
48
  const secretValueInEnv = getEnvironmentVariable(key);
25
49
  if (secretValueInEnv) return secretValueInEnv;
26
- else throw new Error(`Missing key "${key}" for ${pathStr} in load(secretsMap={})`);
27
50
  }
28
- } else if (typeof value === "object" && value !== null && !Array.isArray(value) && "lc" in value && "type" in value && "id" in value && value.lc === 1 && value.type === "not_implemented") {
29
- const serialized = value;
51
+ throw new Error(`Missing secret "${key}" at ${pathStr}`);
52
+ }
53
+ if ("lc" in record && "type" in record && "id" in record && record.lc === 1 && record.type === "not_implemented") {
54
+ const serialized = record;
30
55
  const str = JSON.stringify(serialized);
31
56
  throw new Error(`Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`);
32
- } else if (typeof value === "object" && value !== null && !Array.isArray(value) && "lc" in value && "type" in value && "id" in value && "kwargs" in value && value.lc === 1) {
33
- const serialized = value;
57
+ }
58
+ if ("lc" in record && "type" in record && "id" in record && "kwargs" in record && record.lc === 1 && record.type === "constructor") {
59
+ const serialized = record;
34
60
  const str = JSON.stringify(serialized);
35
61
  const [name, ...namespaceReverse] = serialized.id.slice().reverse();
36
62
  const namespace = namespaceReverse.reverse();
@@ -64,26 +90,60 @@ async function reviver(value) {
64
90
  if (typeof builder !== "function") throw new Error(`Invalid identifer: ${pathStr} -> ${str}`);
65
91
  const kwargs = await reviver.call({
66
92
  ...this,
67
- path: [...path, "kwargs"]
93
+ path: [...path, "kwargs"],
94
+ depth: depth + 1
68
95
  }, serialized.kwargs);
69
- if (serialized.type === "constructor") {
70
- const instance = new builder(mapKeys(kwargs, keyFromJson, combineAliasesAndInvert(builder)));
71
- Object.defineProperty(instance.constructor, "name", { value: name });
72
- return instance;
73
- } else throw new Error(`Invalid type: ${pathStr} -> ${str}`);
74
- } else if (typeof value === "object" && value !== null) if (Array.isArray(value)) return Promise.all(value.map((v, i) => reviver.call({
75
- ...this,
76
- path: [...path, `${i}`]
77
- }, v)));
78
- else return Object.fromEntries(await Promise.all(Object.entries(value).map(async ([key, value$1]) => [key, await reviver.call({
96
+ const instance = new builder(mapKeys(kwargs, keyFromJson, combineAliasesAndInvert(builder)));
97
+ Object.defineProperty(instance.constructor, "name", { value: name });
98
+ return instance;
99
+ }
100
+ const result = {};
101
+ for (const [key, val] of Object.entries(record)) result[key] = await reviver.call({
79
102
  ...this,
80
- path: [...path, key]
81
- }, value$1)])));
82
- return value;
103
+ path: [...path, key],
104
+ depth: depth + 1
105
+ }, val);
106
+ return result;
83
107
  }
84
- async function load(text, mappings) {
108
+ /**
109
+ * Load a LangChain object from a JSON string.
110
+ *
111
+ * @param text - The JSON string to parse and load.
112
+ * @param options - Options for loading.
113
+ * @returns The loaded LangChain object.
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * import { load } from "@langchain/core/load";
118
+ * import { AIMessage } from "@langchain/core/messages";
119
+ *
120
+ * // Basic usage - secrets must be provided explicitly
121
+ * const msg = await load<AIMessage>(jsonString);
122
+ *
123
+ * // With secrets from a map
124
+ * const msg = await load<AIMessage>(jsonString, {
125
+ * secretsMap: { OPENAI_API_KEY: "sk-..." }
126
+ * });
127
+ *
128
+ * // Allow loading secrets from environment (use with caution)
129
+ * const msg = await load<AIMessage>(jsonString, {
130
+ * secretsFromEnv: true
131
+ * });
132
+ * ```
133
+ */
134
+ async function load(text, options) {
85
135
  const json = JSON.parse(text);
86
- return reviver.call({ ...mappings }, json);
136
+ const context = {
137
+ optionalImportsMap: options?.optionalImportsMap ?? {},
138
+ optionalImportEntrypoints: options?.optionalImportEntrypoints ?? [],
139
+ secretsMap: options?.secretsMap ?? {},
140
+ secretsFromEnv: options?.secretsFromEnv ?? false,
141
+ importMap: options?.importMap ?? {},
142
+ path: ["$"],
143
+ depth: 0,
144
+ maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH
145
+ };
146
+ return reviver.call(context, json);
87
147
  }
88
148
 
89
149
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["constructor: typeof Serializable","aliases: { [key: string]: string }","value: unknown","coreImportMap","module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null","defaultOptionalImportEntrypoints","optionalImportEntrypoints","finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"]","importMapKey: string","value","text: string","mappings?: {\n secretsMap?: SecretMap;\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n importMap?: Record<string, unknown>;\n }"],"sources":["../../src/load/index.ts"],"sourcesContent":["import {\n Serializable,\n SerializedConstructor,\n SerializedNotImplemented,\n SerializedSecret,\n get_lc_unique_name,\n} from \"./serializable.js\";\nimport { optionalImportEntrypoints as defaultOptionalImportEntrypoints } from \"./import_constants.js\";\nimport * as coreImportMap from \"./import_map.js\";\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nimport { type SerializedFields, keyFromJson, mapKeys } from \"./map_keys.js\";\nimport { getEnvironmentVariable } from \"../utils/env.js\";\n\nfunction combineAliasesAndInvert(constructor: typeof Serializable) {\n const aliases: { [key: string]: string } = {};\n for (\n let current = constructor;\n current && current.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n Object.assign(aliases, Reflect.get(current.prototype, \"lc_aliases\"));\n }\n return Object.entries(aliases).reduce((acc, [key, value]) => {\n acc[value] = key;\n return acc;\n }, {} as Record<string, string>);\n}\n\nasync function reviver(\n this: {\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n secretsMap?: SecretMap;\n importMap?: Record<string, unknown>;\n path?: string[];\n },\n value: unknown\n): Promise<unknown> {\n const {\n optionalImportsMap = {},\n optionalImportEntrypoints = [],\n importMap = {},\n secretsMap = {},\n path = [\"$\"],\n } = this;\n const pathStr = path.join(\".\");\n if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"lc\" in value &&\n \"type\" in value &&\n \"id\" in value &&\n value.lc === 1 &&\n value.type === \"secret\"\n ) {\n const serialized = value as SerializedSecret;\n const [key] = serialized.id;\n if (key in secretsMap) {\n return secretsMap[key as keyof SecretMap];\n } else {\n const secretValueInEnv = getEnvironmentVariable(key);\n if (secretValueInEnv) {\n return secretValueInEnv;\n } else {\n throw new Error(\n `Missing key \"${key}\" for ${pathStr} in load(secretsMap={})`\n );\n }\n }\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"lc\" in value &&\n \"type\" in value &&\n \"id\" in value &&\n value.lc === 1 &&\n value.type === \"not_implemented\"\n ) {\n const serialized = value as SerializedNotImplemented;\n const str = JSON.stringify(serialized);\n throw new Error(\n `Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`\n );\n } else if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n \"lc\" in value &&\n \"type\" in value &&\n \"id\" in value &&\n \"kwargs\" in value &&\n value.lc === 1\n ) {\n const serialized = value as SerializedConstructor;\n const str = JSON.stringify(serialized);\n const [name, ...namespaceReverse] = serialized.id.slice().reverse();\n const namespace = namespaceReverse.reverse();\n const importMaps = { langchain_core: coreImportMap, langchain: importMap };\n\n let module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null = null;\n\n const optionalImportNamespaceAliases = [namespace.join(\"/\")];\n if (namespace[0] === \"langchain_community\") {\n optionalImportNamespaceAliases.push(\n [\"langchain\", ...namespace.slice(1)].join(\"/\")\n );\n }\n const matchingNamespaceAlias = optionalImportNamespaceAliases.find(\n (alias) => alias in optionalImportsMap\n );\n if (\n defaultOptionalImportEntrypoints\n .concat(optionalImportEntrypoints)\n .includes(namespace.join(\"/\")) ||\n matchingNamespaceAlias\n ) {\n if (matchingNamespaceAlias !== undefined) {\n module = await optionalImportsMap[\n matchingNamespaceAlias as keyof typeof optionalImportsMap\n ];\n } else {\n throw new Error(\n `Missing key \"${namespace.join(\n \"/\"\n )}\" for ${pathStr} in load(optionalImportsMap={})`\n );\n }\n } else {\n let finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"];\n // Currently, we only support langchain and langchain_core imports.\n if (namespace[0] === \"langchain\" || namespace[0] === \"langchain_core\") {\n finalImportMap = importMaps[namespace[0]];\n namespace.shift();\n } else {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // The root namespace \"langchain\" is not a valid import.\n if (namespace.length === 0) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Find the longest matching namespace.\n let importMapKey: string;\n do {\n importMapKey = namespace.join(\"__\");\n if (importMapKey in finalImportMap) {\n break;\n } else {\n namespace.pop();\n }\n } while (namespace.length > 0);\n\n // If no matching namespace is found, throw an error.\n if (importMapKey in finalImportMap) {\n module = finalImportMap[importMapKey as keyof typeof finalImportMap];\n }\n }\n\n if (typeof module !== \"object\" || module === null) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Extract the builder from the import map.\n const builder =\n // look for a named export with the same name as the class\n module[name as keyof typeof module] ??\n // look for an export with a lc_name property matching the class name\n // this is necessary for classes that are minified\n Object.values(module).find(\n (v) =>\n typeof v === \"function\" &&\n get_lc_unique_name(v as typeof Serializable) === name\n );\n if (typeof builder !== \"function\") {\n throw new Error(`Invalid identifer: ${pathStr} -> ${str}`);\n }\n\n // Recurse on the arguments, which may be serialized objects themselves\n const kwargs = await reviver.call(\n { ...this, path: [...path, \"kwargs\"] },\n serialized.kwargs\n );\n\n // Construct the object\n if (serialized.type === \"constructor\") {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const instance = new (builder as any)(\n mapKeys(\n kwargs as SerializedFields,\n keyFromJson,\n combineAliasesAndInvert(builder)\n )\n );\n\n // Minification in severless/edge runtimes will mange the\n // name of classes presented in traces. As the names in import map\n // are present as-is even with minification, use these names instead\n Object.defineProperty(instance.constructor, \"name\", { value: name });\n\n return instance;\n } else {\n throw new Error(`Invalid type: ${pathStr} -> ${str}`);\n }\n } else if (typeof value === \"object\" && value !== null) {\n if (Array.isArray(value)) {\n return Promise.all(\n value.map((v, i) =>\n reviver.call({ ...this, path: [...path, `${i}`] }, v)\n )\n );\n } else {\n return Object.fromEntries(\n await Promise.all(\n Object.entries(value).map(async ([key, value]) => [\n key,\n await reviver.call({ ...this, path: [...path, key] }, value),\n ])\n )\n );\n }\n }\n return value;\n}\n\nexport async function load<T>(\n text: string,\n mappings?: {\n secretsMap?: SecretMap;\n optionalImportsMap?: OptionalImportMap;\n optionalImportEntrypoints?: string[];\n importMap?: Record<string, unknown>;\n }\n): Promise<T> {\n const json = JSON.parse(text);\n return reviver.call({ ...mappings }, json) as Promise<T>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["constructor: typeof Serializable","aliases: { [key: string]: string }","value: unknown","coreImportMap","module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null","defaultOptionalImportEntrypoints","optionalImportEntrypoints","finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"]","importMapKey: string","result: Record<string, unknown>","text: string","options?: LoadOptions","context: ReviverContext"],"sources":["../../src/load/index.ts"],"sourcesContent":["/**\n * Load LangChain objects from JSON strings or objects.\n *\n * ## How it works\n *\n * Each `Serializable` LangChain object has a unique identifier (its \"class path\"),\n * which is a list of strings representing the module path and class name. For example:\n *\n * - `AIMessage` -> `[\"langchain_core\", \"messages\", \"ai\", \"AIMessage\"]`\n * - `ChatPromptTemplate` -> `[\"langchain_core\", \"prompts\", \"chat\", \"ChatPromptTemplate\"]`\n *\n * When deserializing, the class path is validated against supported namespaces.\n *\n * ## Security model\n *\n * The `secretsFromEnv` parameter controls whether secrets can be loaded from environment\n * variables:\n *\n * - `false` (default): Secrets must be provided in `secretsMap`. If a secret is not\n * found, `null` is returned instead of loading from environment variables.\n * - `true`: If a secret is not found in `secretsMap`, it will be loaded from\n * environment variables. Use this only in trusted environments.\n *\n * ### Injection protection (escape-based)\n *\n * During serialization, plain objects that contain an `'lc'` key are escaped by wrapping\n * them: `{\"__lc_escaped__\": {...}}`. During deserialization, escaped objects are unwrapped\n * and returned as plain objects, NOT instantiated as LC objects.\n *\n * This is an allowlist approach: only objects explicitly produced by\n * `Serializable.toJSON()` (which are NOT escaped) are treated as LC objects;\n * everything else is user data.\n *\n * @module\n */\n\nimport {\n Serializable,\n SerializedConstructor,\n SerializedNotImplemented,\n SerializedSecret,\n get_lc_unique_name,\n} from \"./serializable.js\";\nimport { optionalImportEntrypoints as defaultOptionalImportEntrypoints } from \"./import_constants.js\";\nimport * as coreImportMap from \"./import_map.js\";\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nimport { type SerializedFields, keyFromJson, mapKeys } from \"./map_keys.js\";\nimport { getEnvironmentVariable } from \"../utils/env.js\";\nimport { isEscapedObject, unescapeValue } from \"./validation.js\";\n\n/**\n * Options for loading serialized LangChain objects.\n *\n * @remarks\n * **Security considerations:**\n *\n * Deserialization can instantiate arbitrary classes from the allowed namespaces.\n * When loading untrusted data, be aware that:\n *\n * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the\n * deserializer to read environment variables, which could leak secrets if\n * the serialized data contains malicious secret references.\n *\n * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes\n * can be instantiated. Never populate these from user input. Only include\n * modules you explicitly trust.\n *\n * 3. **Class instantiation**: Allowed classes will have their constructors called\n * with the deserialized kwargs. If a class performs side effects in its\n * constructor (network calls, file I/O, etc.), those will execute.\n */\nexport interface LoadOptions {\n /**\n * A map of secrets to load. Keys are secret identifiers, values are the secret values.\n *\n * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is\n * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment\n * variables (if not found there either, an error is thrown).\n */\n secretsMap?: SecretMap;\n\n /**\n * Whether to load secrets from environment variables when not found in `secretsMap`.\n *\n * @default false\n *\n * @remarks\n * **Security warning:** Setting this to `true` allows the deserializer to read\n * environment variables, which could be a security risk if the serialized data\n * is not trusted. Only set this to `true` when deserializing data from trusted\n * sources (e.g., your own database, not user input).\n */\n secretsFromEnv?: boolean;\n\n /**\n * A map of optional imports. Keys are namespace paths (e.g., \"langchain_community/llms\"),\n * values are the imported modules.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Classes in these modules can be instantiated with attacker-controlled kwargs\n * if the serialized data is untrusted.\n */\n optionalImportsMap?: OptionalImportMap;\n\n /**\n * Additional optional import entrypoints to allow beyond the defaults.\n *\n * @remarks\n * **Security warning:** This extends which namespace paths are considered valid\n * for deserialization. Never populate this array with values derived from user\n * input. Each entrypoint you add expands the attack surface for deserialization.\n */\n optionalImportEntrypoints?: string[];\n\n /**\n * Additional import map for the \"langchain\" namespace.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Any class exposed through this map can be instantiated with attacker-controlled\n * kwargs if the serialized data is untrusted.\n */\n importMap?: Record<string, unknown>;\n\n /**\n * Maximum recursion depth allowed during deserialization.\n *\n * @default 50\n *\n * @remarks\n * This limit protects against denial-of-service attacks using deeply nested\n * JSON structures that could cause stack overflow. If your legitimate data\n * requires deeper nesting, you can increase this limit.\n */\n maxDepth?: number;\n}\n\n/**\n * Default maximum recursion depth for deserialization.\n * This provides protection against DoS attacks via deeply nested structures.\n */\nconst DEFAULT_MAX_DEPTH = 50;\n\nfunction combineAliasesAndInvert(constructor: typeof Serializable) {\n const aliases: { [key: string]: string } = {};\n for (\n let current = constructor;\n current && current.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n Object.assign(aliases, Reflect.get(current.prototype, \"lc_aliases\"));\n }\n return Object.entries(aliases).reduce((acc, [key, value]) => {\n acc[value] = key;\n return acc;\n }, {} as Record<string, string>);\n}\n\ninterface ReviverContext {\n optionalImportsMap: OptionalImportMap;\n optionalImportEntrypoints: string[];\n secretsMap: SecretMap;\n secretsFromEnv: boolean;\n importMap: Record<string, unknown>;\n path: string[];\n depth: number;\n maxDepth: number;\n}\n\n/**\n * Recursively revive a value, handling escape markers and LC objects.\n *\n * This function handles:\n * 1. Escaped dicts - unwrapped and returned as plain objects\n * 2. LC secret objects - resolved from secretsMap or env\n * 3. LC constructor objects - instantiated\n * 4. Regular objects/arrays - recursed into\n */\nasync function reviver(this: ReviverContext, value: unknown): Promise<unknown> {\n const {\n optionalImportsMap,\n optionalImportEntrypoints,\n importMap,\n secretsMap,\n secretsFromEnv,\n path,\n depth,\n maxDepth,\n } = this;\n const pathStr = path.join(\".\");\n\n // Check recursion depth to prevent DoS via deeply nested structures\n if (depth > maxDepth) {\n throw new Error(\n `Maximum recursion depth (${maxDepth}) exceeded during deserialization. ` +\n `This may indicate a malicious payload or you may need to increase maxDepth.`\n );\n }\n\n // If not an object, return as-is\n if (typeof value !== \"object\" || value == null) {\n return value;\n }\n\n // Handle arrays - recurse into elements\n if (Array.isArray(value)) {\n return Promise.all(\n value.map((v, i) =>\n reviver.call({ ...this, path: [...path, `${i}`], depth: depth + 1 }, v)\n )\n );\n }\n\n // It's an object - check for escape marker FIRST\n const record = value as Record<string, unknown>;\n if (isEscapedObject(record)) {\n // This is an escaped user object - unwrap and return as-is (no LC processing)\n return unescapeValue(record);\n }\n\n // Check for LC secret object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"secret\"\n ) {\n const serialized = record as unknown as SerializedSecret;\n const [key] = serialized.id;\n if (key in secretsMap) {\n return secretsMap[key as keyof SecretMap];\n } else if (secretsFromEnv) {\n const secretValueInEnv = getEnvironmentVariable(key);\n if (secretValueInEnv) {\n return secretValueInEnv;\n }\n }\n throw new Error(`Missing secret \"${key}\" at ${pathStr}`);\n }\n\n // Check for LC not_implemented object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"not_implemented\"\n ) {\n const serialized = record as unknown as SerializedNotImplemented;\n const str = JSON.stringify(serialized);\n throw new Error(\n `Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`\n );\n }\n\n // Check for LC constructor object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n \"kwargs\" in record &&\n record.lc === 1 &&\n record.type === \"constructor\"\n ) {\n const serialized = record as unknown as SerializedConstructor;\n const str = JSON.stringify(serialized);\n const [name, ...namespaceReverse] = serialized.id.slice().reverse();\n const namespace = namespaceReverse.reverse();\n const importMaps = { langchain_core: coreImportMap, langchain: importMap };\n\n let module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null = null;\n\n const optionalImportNamespaceAliases = [namespace.join(\"/\")];\n if (namespace[0] === \"langchain_community\") {\n optionalImportNamespaceAliases.push(\n [\"langchain\", ...namespace.slice(1)].join(\"/\")\n );\n }\n const matchingNamespaceAlias = optionalImportNamespaceAliases.find(\n (alias) => alias in optionalImportsMap\n );\n if (\n defaultOptionalImportEntrypoints\n .concat(optionalImportEntrypoints)\n .includes(namespace.join(\"/\")) ||\n matchingNamespaceAlias\n ) {\n if (matchingNamespaceAlias !== undefined) {\n module = await optionalImportsMap[\n matchingNamespaceAlias as keyof typeof optionalImportsMap\n ];\n } else {\n throw new Error(\n `Missing key \"${namespace.join(\n \"/\"\n )}\" for ${pathStr} in load(optionalImportsMap={})`\n );\n }\n } else {\n let finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"];\n // Currently, we only support langchain and langchain_core imports.\n if (namespace[0] === \"langchain\" || namespace[0] === \"langchain_core\") {\n finalImportMap = importMaps[namespace[0]];\n namespace.shift();\n } else {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // The root namespace \"langchain\" is not a valid import.\n if (namespace.length === 0) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Find the longest matching namespace.\n let importMapKey: string;\n do {\n importMapKey = namespace.join(\"__\");\n if (importMapKey in finalImportMap) {\n break;\n } else {\n namespace.pop();\n }\n } while (namespace.length > 0);\n\n // If no matching namespace is found, throw an error.\n if (importMapKey in finalImportMap) {\n module = finalImportMap[importMapKey as keyof typeof finalImportMap];\n }\n }\n\n if (typeof module !== \"object\" || module === null) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Extract the builder from the import map.\n const builder =\n // look for a named export with the same name as the class\n module[name as keyof typeof module] ??\n // look for an export with a lc_name property matching the class name\n // this is necessary for classes that are minified\n Object.values(module).find(\n (v) =>\n typeof v === \"function\" &&\n get_lc_unique_name(v as typeof Serializable) === name\n );\n if (typeof builder !== \"function\") {\n throw new Error(`Invalid identifer: ${pathStr} -> ${str}`);\n }\n\n // Recurse on the arguments, which may be serialized objects themselves\n const kwargs = await reviver.call(\n { ...this, path: [...path, \"kwargs\"], depth: depth + 1 },\n serialized.kwargs\n );\n\n // Construct the object\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const instance = new (builder as any)(\n mapKeys(\n kwargs as SerializedFields,\n keyFromJson,\n combineAliasesAndInvert(builder)\n )\n );\n\n // Minification in severless/edge runtimes will mange the\n // name of classes presented in traces. As the names in import map\n // are present as-is even with minification, use these names instead\n Object.defineProperty(instance.constructor, \"name\", { value: name });\n\n return instance;\n }\n\n // Regular object - recurse into values\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n result[key] = await reviver.call(\n { ...this, path: [...path, key], depth: depth + 1 },\n val\n );\n }\n return result;\n}\n\n/**\n * Load a LangChain object from a JSON string.\n *\n * @param text - The JSON string to parse and load.\n * @param options - Options for loading.\n * @returns The loaded LangChain object.\n *\n * @example\n * ```typescript\n * import { load } from \"@langchain/core/load\";\n * import { AIMessage } from \"@langchain/core/messages\";\n *\n * // Basic usage - secrets must be provided explicitly\n * const msg = await load<AIMessage>(jsonString);\n *\n * // With secrets from a map\n * const msg = await load<AIMessage>(jsonString, {\n * secretsMap: { OPENAI_API_KEY: \"sk-...\" }\n * });\n *\n * // Allow loading secrets from environment (use with caution)\n * const msg = await load<AIMessage>(jsonString, {\n * secretsFromEnv: true\n * });\n * ```\n */\nexport async function load<T>(text: string, options?: LoadOptions): Promise<T> {\n const json = JSON.parse(text);\n\n const context: ReviverContext = {\n optionalImportsMap: options?.optionalImportsMap ?? {},\n optionalImportEntrypoints: options?.optionalImportEntrypoints ?? [],\n secretsMap: options?.secretsMap ?? {},\n secretsFromEnv: options?.secretsFromEnv ?? false,\n importMap: options?.importMap ?? {},\n path: [\"$\"],\n depth: 0,\n maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n };\n\n return reviver.call(context, json) as Promise<T>;\n}\n"],"mappings":";;;;;;;;;;;;AAoJA,MAAM,oBAAoB;AAE1B,SAAS,wBAAwBA,aAAkC;CACjE,MAAMC,UAAqC,CAAE;AAC7C,MACE,IAAI,UAAU,aACd,WAAW,QAAQ,WACnB,UAAU,OAAO,eAAe,QAAQ,EAExC,OAAO,OAAO,SAAS,QAAQ,IAAI,QAAQ,WAAW,aAAa,CAAC;AAEtE,QAAO,OAAO,QAAQ,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,MAAM,KAAK;EAC3D,IAAI,SAAS;AACb,SAAO;CACR,GAAE,CAAE,EAA2B;AACjC;;;;;;;;;;AAsBD,eAAe,QAA8BC,OAAkC;CAC7E,MAAM,EACJ,oBACA,wDACA,WACA,YACA,gBACA,MACA,OACA,UACD,GAAG;CACJ,MAAM,UAAU,KAAK,KAAK,IAAI;AAG9B,KAAI,QAAQ,SACV,OAAM,IAAI,MACR,CAAC,yBAAyB,EAAE,SAAS,8GAAmC,CACO;AAKnF,KAAI,OAAO,UAAU,YAAY,SAAS,KACxC,QAAO;AAIT,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,QAAQ,IACb,MAAM,IAAI,CAAC,GAAG,MACZ,QAAQ,KAAK;EAAE,GAAG;EAAM,MAAM,CAAC,GAAG,MAAM,GAAG,GAAG,AAAC;EAAE,OAAO,QAAQ;CAAG,GAAE,EAAE,CACxE,CACF;CAIH,MAAM,SAAS;AACf,KAAI,gBAAgB,OAAO,CAEzB,QAAO,cAAc,OAAO;AAI9B,KACE,QAAQ,UACR,UAAU,UACV,QAAQ,UACR,OAAO,OAAO,KACd,OAAO,SAAS,UAChB;EACA,MAAM,aAAa;EACnB,MAAM,CAAC,IAAI,GAAG,WAAW;AACzB,MAAI,OAAO,WACT,QAAO,WAAW;WACT,gBAAgB;GACzB,MAAM,mBAAmB,uBAAuB,IAAI;AACpD,OAAI,iBACF,QAAO;EAEV;AACD,QAAM,IAAI,MAAM,CAAC,gBAAgB,EAAE,IAAI,KAAK,EAAE,SAAS;CACxD;AAGD,KACE,QAAQ,UACR,UAAU,UACV,QAAQ,UACR,OAAO,OAAO,KACd,OAAO,SAAS,mBAChB;EACA,MAAM,aAAa;EACnB,MAAM,MAAM,KAAK,UAAU,WAAW;AACtC,QAAM,IAAI,MACR,CAAC,+DAA+D,EAAE,QAAQ,IAAI,EAAE,KAAK;CAExF;AAGD,KACE,QAAQ,UACR,UAAU,UACV,QAAQ,UACR,YAAY,UACZ,OAAO,OAAO,KACd,OAAO,SAAS,eAChB;EACA,MAAM,aAAa;EACnB,MAAM,MAAM,KAAK,UAAU,WAAW;EACtC,MAAM,CAAC,MAAM,GAAG,iBAAiB,GAAG,WAAW,GAAG,OAAO,CAAC,SAAS;EACnE,MAAM,YAAY,iBAAiB,SAAS;EAC5C,MAAM,aAAa;GAAE,gBAAgBC;GAAe,WAAW;EAAW;EAE1E,IAAIC,SAIO;EAEX,MAAM,iCAAiC,CAAC,UAAU,KAAK,IAAI,AAAC;AAC5D,MAAI,UAAU,OAAO,uBACnB,+BAA+B,KAC7B,CAAC,aAAa,GAAG,UAAU,MAAM,EAAE,AAAC,EAAC,KAAK,IAAI,CAC/C;EAEH,MAAM,yBAAyB,+BAA+B,KAC5D,CAAC,UAAU,SAAS,mBACrB;AACD,MACEC,0BACG,OAAOC,4BAA0B,CACjC,SAAS,UAAU,KAAK,IAAI,CAAC,IAChC,uBAEA,KAAI,2BAA2B,QAC7B,SAAS,MAAM,mBACb;MAGF,OAAM,IAAI,MACR,CAAC,aAAa,EAAE,UAAU,KACxB,IACD,CAAC,MAAM,EAAE,QAAQ,+BAA+B,CAAC;OAGjD;GACL,IAAIC;AAIJ,OAAI,UAAU,OAAO,eAAe,UAAU,OAAO,kBAAkB;IACrE,iBAAiB,WAAW,UAAU;IACtC,UAAU,OAAO;GAClB,MACC,OAAM,IAAI,MAAM,CAAC,mBAAmB,EAAE,QAAQ,IAAI,EAAE,KAAK;AAI3D,OAAI,UAAU,WAAW,EACvB,OAAM,IAAI,MAAM,CAAC,mBAAmB,EAAE,QAAQ,IAAI,EAAE,KAAK;GAI3D,IAAIC;AACJ,MAAG;IACD,eAAe,UAAU,KAAK,KAAK;AACnC,QAAI,gBAAgB,eAClB;SAEA,UAAU,KAAK;GAElB,SAAQ,UAAU,SAAS;AAG5B,OAAI,gBAAgB,gBAClB,SAAS,eAAe;EAE3B;AAED,MAAI,OAAO,WAAW,YAAY,WAAW,KAC3C,OAAM,IAAI,MAAM,CAAC,mBAAmB,EAAE,QAAQ,IAAI,EAAE,KAAK;EAI3D,MAAM,UAEJ,OAAO,SAGP,OAAO,OAAO,OAAO,CAAC,KACpB,CAAC,MACC,OAAO,MAAM,cACb,mBAAmB,EAAyB,KAAK,KACpD;AACH,MAAI,OAAO,YAAY,WACrB,OAAM,IAAI,MAAM,CAAC,mBAAmB,EAAE,QAAQ,IAAI,EAAE,KAAK;EAI3D,MAAM,SAAS,MAAM,QAAQ,KAC3B;GAAE,GAAG;GAAM,MAAM,CAAC,GAAG,MAAM,QAAS;GAAE,OAAO,QAAQ;EAAG,GACxD,WAAW,OACZ;EAID,MAAM,WAAW,IAAK,QACpB,QACE,QACA,aACA,wBAAwB,QAAQ,CACjC;EAMH,OAAO,eAAe,SAAS,aAAa,QAAQ,EAAE,OAAO,KAAM,EAAC;AAEpE,SAAO;CACR;CAGD,MAAMC,SAAkC,CAAE;AAC1C,MAAK,MAAM,CAAC,KAAK,IAAI,IAAI,OAAO,QAAQ,OAAO,EAC7C,OAAO,OAAO,MAAM,QAAQ,KAC1B;EAAE,GAAG;EAAM,MAAM,CAAC,GAAG,MAAM,GAAI;EAAE,OAAO,QAAQ;CAAG,GACnD,IACD;AAEH,QAAO;AACR;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BD,eAAsB,KAAQC,MAAcC,SAAmC;CAC7E,MAAM,OAAO,KAAK,MAAM,KAAK;CAE7B,MAAMC,UAA0B;EAC9B,oBAAoB,SAAS,sBAAsB,CAAE;EACrD,2BAA2B,SAAS,6BAA6B,CAAE;EACnE,YAAY,SAAS,cAAc,CAAE;EACrC,gBAAgB,SAAS,kBAAkB;EAC3C,WAAW,SAAS,aAAa,CAAE;EACnC,MAAM,CAAC,GAAI;EACX,OAAO;EACP,UAAU,SAAS,YAAY;CAChC;AAED,QAAO,QAAQ,KAAK,SAAS,KAAK;AACnC"}
@@ -1,5 +1,6 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_map_keys = require('./map_keys.cjs');
3
+ const require_validation = require('./validation.cjs');
3
4
 
4
5
  //#region src/load/serializable.ts
5
6
  var serializable_exports = {};
@@ -122,11 +123,15 @@ var Serializable = class Serializable {
122
123
  }
123
124
  if (last in read && read[last] !== void 0) write[last] = write[last] || read[last];
124
125
  });
126
+ const escapedKwargs = {};
127
+ for (const [key, value] of Object.entries(kwargs)) escapedKwargs[key] = require_validation.escapeIfNeeded(value);
128
+ const kwargsWithSecrets = Object.keys(secrets).length ? replaceSecrets(escapedKwargs, secrets) : escapedKwargs;
129
+ const processedKwargs = require_map_keys.mapKeys(kwargsWithSecrets, require_map_keys.keyToJson, aliases);
125
130
  return {
126
131
  lc: 1,
127
132
  type: "constructor",
128
133
  id: this.lc_id,
129
- kwargs: require_map_keys.mapKeys(Object.keys(secrets).length ? replaceSecrets(kwargs, secrets) : kwargs, require_map_keys.keyToJson, aliases)
134
+ kwargs: processedKwargs
130
135
  };
131
136
  }
132
137
  toJSONNotImplemented() {