diff --git a/packages/core/package.json b/packages/core/package.json index 4a51d2c15d..c717403532 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -132,6 +132,7 @@ "devDependencies": { "ajv": "^8.17.1", "bunchee": "5.3.2", + "change-case": "^5.4.4", "natural": "^8.0.1" }, "dependencies": { diff --git a/packages/core/src/schema/index.ts b/packages/core/src/schema/index.ts index a38ba9975b..6abcaac5fd 100644 --- a/packages/core/src/schema/index.ts +++ b/packages/core/src/schema/index.ts @@ -1,4 +1,5 @@ export * from "./node"; +export { DATA_KEY, TYPE_KEY, fromDocStore, type DocJson } from "./python"; export { FileReader, TransformComponent, type BaseReader } from "./type"; export { EngineResponse } from "./type/engine–response"; export * from "./zod"; diff --git a/packages/core/src/schema/node.ts b/packages/core/src/schema/node.ts index 50ab9a9733..3d6725f8a4 100644 --- a/packages/core/src/schema/node.ts +++ b/packages/core/src/schema/node.ts @@ -10,11 +10,11 @@ export enum NodeRelationship { } export enum ObjectType { - TEXT = "TEXT", - IMAGE = "IMAGE", - INDEX = "INDEX", - DOCUMENT = "DOCUMENT", - IMAGE_DOCUMENT = "IMAGE_DOCUMENT", + TEXT = "1", + IMAGE = "2", + INDEX = "3", + DOCUMENT = "4", + IMAGE_DOCUMENT = "5", // Python side doesn't have this enum } export enum MetadataMode { @@ -76,7 +76,6 @@ export abstract class BaseNode { excludedEmbedMetadataKeys, excludedLlmMetadataKeys, relationships, - hash, embedding, } = init || {}; this.id_ = id_ ?? randomUUID(); @@ -177,13 +176,12 @@ export abstract class BaseNode { return { ...this, type: this.type, - // hash is an accessor property, so it's not included in the rest operator - hash: this.hash, + // no `hash` here to align with Python side }; } clone(): BaseNode { - return jsonToNode(this.toMutableJSON()) as BaseNode; + return jsonToNode(this.toMutableJSON(), this.type); } /** @@ -224,27 +222,19 @@ export class TextNode extends BaseNode { init; this.text = text ?? ""; this.textTemplate = textTemplate ?? ""; - if (startCharIdx) { + if (startCharIdx !== undefined) { this.startCharIdx = startCharIdx; } - if (endCharIdx) { + if (endCharIdx !== undefined) { this.endCharIdx = endCharIdx; } this.metadataSeparator = metadataSeparator ?? "\n"; } - /** - * Generate a hash of the text node. - * The ID is not part of the hash as it can change independent of content. - * @returns - */ generateHash() { const hashFunction = createSHA256(); - hashFunction.update(`type=${this.type}`); - hashFunction.update( - `startCharIdx=${this.startCharIdx} endCharIdx=${this.endCharIdx}`, - ); - hashFunction.update(this.getContent(MetadataMode.ALL)); + const docIdentity = this.text + JSON.stringify(this.metadata); + hashFunction.update(docIdentity); return hashFunction.digest(); } diff --git a/packages/core/src/schema/python.ts b/packages/core/src/schema/python.ts new file mode 100644 index 0000000000..d789cc2e75 --- /dev/null +++ b/packages/core/src/schema/python.ts @@ -0,0 +1,72 @@ +/** + * Python adapter for the schema. + */ +import { jsonToNode, ObjectType } from "./node"; + +export const TYPE_KEY = "__type__"; +export const DATA_KEY = "__data__"; + +async function camelCaseJson(json: Record) { + const { camelCase } = await import("change-case"); + return Object.entries(json).reduce( + (acc, [key, value]) => { + acc[ + camelCase(key, { + suffixCharacters: "_", + }) + ] = value; + return acc; + }, + {} as Record, + ); +} + +const PYTHON_TO_JS_TYPE_MAP = { + "1": ObjectType.TEXT, + "2": ObjectType.IMAGE, + "3": ObjectType.INDEX, + "4": ObjectType.DOCUMENT, +}; + +const LEGACY_JS_MAP = { + TEXT: ObjectType.TEXT, + IMAGE: ObjectType.IMAGE, + INDEX: ObjectType.INDEX, + DOCUMENT: ObjectType.DOCUMENT, + IMAGE_DOCUMENT: ObjectType.DOCUMENT, +}; + +export type DocJson = { + [TYPE_KEY]: string; + [DATA_KEY]: string; +}; + +async function fromImpl(data: Record) { + const convertedJson = await camelCaseJson(data); + if (convertedJson.relationships) { + for (const [key, value] of Object.entries(convertedJson.relationships)) { + if (typeof value === "object" && value !== null) { + convertedJson.relationships[key] = await camelCaseJson(value); + } else if (Array.isArray(value)) { + convertedJson.relationships[key] = await Promise.all( + value.map((v) => camelCaseJson(v)), + ); + } + } + } + return convertedJson; +} + +export async function fromDocStore({ + [TYPE_KEY]: type, + [DATA_KEY]: data, +}: DocJson) { + if (!(type in PYTHON_TO_JS_TYPE_MAP) && !(type in LEGACY_JS_MAP)) { + throw new Error("Invalid type"); + } + const objectType = + PYTHON_TO_JS_TYPE_MAP[type as keyof typeof PYTHON_TO_JS_TYPE_MAP] || + LEGACY_JS_MAP[type as keyof typeof LEGACY_JS_MAP]; + const convertedJson = await fromImpl(JSON.parse(data)); + return jsonToNode(convertedJson, objectType); +} diff --git a/packages/core/tests/decorator.test.ts b/packages/core/tests/decorator.test.ts index 326810104d..a6b3086c19 100644 --- a/packages/core/tests/decorator.test.ts +++ b/packages/core/tests/decorator.test.ts @@ -12,14 +12,17 @@ describe("chunkSizeCheck", () => { env.ENABLE_CHUNK_SIZE_CHECK = "true"; let message = ""; - const consoleMock = vi - .spyOn(console, "warn") - .mockImplementation((msg) => (message += msg + "\n")); + vi.spyOn(console, "warn").mockImplementation( + (msg) => (message += msg + "\n"), + ); Settings.chunkSize = 0; + const node = new TextNode(); expect(message).toEqual(""); node.setContent("a".repeat(1024)); + expect(message).toBe(""); + node.getContent(); expect(message).toContain("is larger than chunk size"); }); }); diff --git a/packages/core/tests/schema-node.test.ts b/packages/core/tests/schema-node.test.ts index 7827fcbd68..074b80ce75 100644 --- a/packages/core/tests/schema-node.test.ts +++ b/packages/core/tests/schema-node.test.ts @@ -1,6 +1,74 @@ -import { Document, TextNode } from "@llamaindex/core/schema"; +import { + Document, + ObjectType, + TextNode, + fromPythonDocStore, +} from "@llamaindex/core/schema"; import { beforeEach, describe, expect, test } from "vitest"; +describe("Python", () => { + test("from python doc store", async () => { + const node = await fromPythonDocStore({ + __data__: JSON.stringify({ + id_: "e86be4a7-2ad0-4c3c-937b-3140f562e7a7", + embedding: null, + metadata: {}, + excluded_embed_metadata_keys: [], + excluded_llm_metadata_keys: [], + relationships: { + "1": { + node_id: "e1fe8fd0-f470-40cd-bc2e-be3a220cef94", + node_type: "4", + metadata: {}, + hash: "191a8fdcf068d3ac831da23cde07a92efe1432243c7f628d1009aa2ecdf6cb03", + class_name: "RelatedNodeInfo", + }, + }, + text: "This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test.", + mimetype: "text/plain", + start_char_idx: 0, + end_char_idx: 1599, + text_template: "{metadata_str}\n\n{content}", + metadata_template: "{key}: {value}", + metadata_seperator: "\n", + class_name: "TextNode", + }), + __type__: "1", + }); + expect(node.startCharIdx).toBe(0); + expect(node.endCharIdx).toBe(1599); + expect(node).toMatchInlineSnapshot(` + { + "embedding": null, + "endCharIdx": 1599, + "excludedEmbedMetadataKeys": [], + "excludedLlmMetadataKeys": [], + "id_": "e86be4a7-2ad0-4c3c-937b-3140f562e7a7", + "metadata": {}, + "metadataSeparator": " + ", + "relationships": { + "1": { + "className": "RelatedNodeInfo", + "hash": "191a8fdcf068d3ac831da23cde07a92efe1432243c7f628d1009aa2ecdf6cb03", + "metadata": {}, + "nodeId": "e1fe8fd0-f470-40cd-bc2e-be3a220cef94", + "nodeType": "4", + }, + }, + "startCharIdx": 0, + "text": "This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test.", + "textTemplate": "{metadata_str} + + {content}", + "type": "1", + } + `); + expect(node.id_).toBe("e86be4a7-2ad0-4c3c-937b-3140f562e7a7"); + expect(node.type).toBe(ObjectType.TEXT); + }); +}); + describe("Document", () => { let document: Document; @@ -10,7 +78,7 @@ describe("Document", () => { test("should generate a hash", () => { expect(document.hash).toMatchInlineSnapshot( - `"1mkNkQC30mZlBBG48DNuG2WSKcTQ32DImC+4JUoVijg="`, + `"oznYDHYUGHArYnhRy9lj63IvEt/rNg1EH5EjwtPU/Pc="`, ); }); @@ -30,7 +98,7 @@ describe("TextNode", () => { test("should generate a hash", () => { expect(node.hash).toMatchInlineSnapshot( - `"nTSKdUTYqR52MPv/brvb4RTGeqedTEqG9QN8KSAj2Do="`, + `"oznYDHYUGHArYnhRy9lj63IvEt/rNg1EH5EjwtPU/Pc="`, ); }); @@ -52,7 +120,6 @@ describe("TextNode", () => { "embedding": undefined, "excludedEmbedMetadataKeys": [], "excludedLlmMetadataKeys": [], - "hash": "Z6SWgFPlalaeblMGQGw0KS3qKgmZdEWXKfzEp/K+QN0=", "id_": Any, "metadata": { "something": 1, @@ -63,7 +130,7 @@ describe("TextNode", () => { "relationships": {}, "text": "Hello World", "textTemplate": "", - "type": "TEXT", + "type": "1", } `, ); diff --git a/packages/llamaindex/src/ingestion/IngestionCache.ts b/packages/llamaindex/src/ingestion/IngestionCache.ts index 353e565f85..796711801e 100644 --- a/packages/llamaindex/src/ingestion/IngestionCache.ts +++ b/packages/llamaindex/src/ingestion/IngestionCache.ts @@ -1,7 +1,11 @@ -import type { BaseNode, TransformComponent } from "@llamaindex/core/schema"; -import { MetadataMode } from "@llamaindex/core/schema"; +import { + type BaseNode, + fromDocStore, + MetadataMode, + type TransformComponent, +} from "@llamaindex/core/schema"; import { createSHA256 } from "@llamaindex/env"; -import { docToJson, jsonToDoc } from "../storage/docStore/utils.js"; +import { docToJson } from "../storage/docStore/utils.js"; import { SimpleKVStore } from "../storage/kvStore/SimpleKVStore.js"; import type { BaseKVStore } from "../storage/kvStore/types.js"; @@ -63,6 +67,8 @@ export class IngestionCache { if (!json || !json[this.nodesKey] || !Array.isArray(json[this.nodesKey])) { return undefined; } - return json[this.nodesKey].map((doc: any) => jsonToDoc(doc)); + return Promise.all( + json[this.nodesKey].map((doc: any) => fromDocStore(doc)), + ); } } diff --git a/packages/llamaindex/src/storage/docStore/KVDocumentStore.ts b/packages/llamaindex/src/storage/docStore/KVDocumentStore.ts index b239c4c69b..94a4bfe355 100644 --- a/packages/llamaindex/src/storage/docStore/KVDocumentStore.ts +++ b/packages/llamaindex/src/storage/docStore/KVDocumentStore.ts @@ -1,11 +1,14 @@ -import type { BaseNode } from "@llamaindex/core/schema"; -import { ObjectType } from "@llamaindex/core/schema"; +import { + type BaseNode, + fromDocStore, + ObjectType, +} from "@llamaindex/core/schema"; import _ from "lodash"; import { DEFAULT_NAMESPACE } from "../constants.js"; import type { BaseKVStore } from "../kvStore/types.js"; import type { RefDocInfo } from "./types.js"; import { BaseDocumentStore } from "./types.js"; -import { docToJson, isValidDocJson, jsonToDoc } from "./utils.js"; +import { docToJson, isValidDocJson } from "./utils.js"; type DocMetaData = { docHash: string; refDocId?: string }; @@ -29,7 +32,7 @@ export class KVDocumentStore extends BaseDocumentStore { for (const key in jsonDict) { const value = jsonDict[key]; if (isValidDocJson(value)) { - docs[key] = jsonToDoc(value); + docs[key] = await fromDocStore(value); } else { console.warn(`Invalid JSON for docId ${key}`); } @@ -94,7 +97,7 @@ export class KVDocumentStore extends BaseDocumentStore { if (!isValidDocJson(json)) { throw new Error(`Invalid JSON for docId ${docId}`); } - return jsonToDoc(json); + return fromDocStore(json); } async getRefDocInfo(refDocId: string): Promise { diff --git a/packages/llamaindex/src/storage/docStore/utils.ts b/packages/llamaindex/src/storage/docStore/utils.ts index 1735b81eea..b2c68a5516 100644 --- a/packages/llamaindex/src/storage/docStore/utils.ts +++ b/packages/llamaindex/src/storage/docStore/utils.ts @@ -1,5 +1,5 @@ import type { BaseNode } from "@llamaindex/core/schema"; -import { Document, ObjectType, TextNode } from "@llamaindex/core/schema"; +import { ObjectType } from "@llamaindex/core/schema"; const TYPE_KEY = "__type__"; const DATA_KEY = "__data__"; @@ -24,31 +24,3 @@ export function docToJson(doc: BaseNode): DocJson { [TYPE_KEY]: doc.type, }; } - -export function jsonToDoc(docDict: DocJson): BaseNode { - const docType = docDict[TYPE_KEY]; - const dataDict = JSON.parse(docDict[DATA_KEY]); - let doc: BaseNode; - - if (docType === ObjectType.DOCUMENT) { - doc = new Document({ - text: dataDict.text, - id_: dataDict.id_, - embedding: dataDict.embedding, - hash: dataDict.hash, - metadata: dataDict.metadata, - }); - } else if (docType === ObjectType.TEXT) { - doc = new TextNode({ - text: dataDict.text, - id_: dataDict.id_, - hash: dataDict.hash, - metadata: dataDict.metadata, - relationships: dataDict.relationships, - }); - } else { - throw new Error(`Unknown doc type: ${docType}`); - } - - return doc; -} diff --git a/packages/llamaindex/src/storage/vectorStore/utils.ts b/packages/llamaindex/src/storage/vectorStore/utils.ts index da40eeb9b8..2484d17661 100644 --- a/packages/llamaindex/src/storage/vectorStore/utils.ts +++ b/packages/llamaindex/src/storage/vectorStore/utils.ts @@ -29,7 +29,7 @@ export function nodeToMetadata( } metadata["_node_content"] = JSON.stringify(rest); - metadata["_node_type"] = node.constructor.name.replace("_", ""); // remove leading underscore to be compatible with Python + metadata["_node_type"] = node.constructor.name.replace("_", ""); metadata["document_id"] = node.sourceNode?.nodeId || "None"; metadata["doc_id"] = node.sourceNode?.nodeId || "None"; diff --git a/packages/llamaindex/tests/VectorStore.test.ts b/packages/llamaindex/tests/VectorStore.test.ts index f44444d773..5efc070b9d 100644 --- a/packages/llamaindex/tests/VectorStore.test.ts +++ b/packages/llamaindex/tests/VectorStore.test.ts @@ -1,4 +1,10 @@ -import { Document, MetadataMode } from "@llamaindex/core/schema"; +import { + Document, + ImageNode, + IndexNode, + MetadataMode, + TextNode, +} from "@llamaindex/core/schema"; import { metadataDictToNode, nodeToMetadata, @@ -46,3 +52,36 @@ describe("Testing VectorStore utils", () => { }).toThrow(); }); }); + +describe("vector store utilities", () => { + test("nodeToMetadata", () => { + { + const node = new Document({ + text: "text", + }); + const metadata = nodeToMetadata(node); + expect(metadata["_node_type"]).toBe("Document"); + } + { + const node = new TextNode({ + text: "text", + }); + const metadata = nodeToMetadata(node); + expect(metadata["_node_type"]).toBe("TextNode"); + } + { + const node = new IndexNode({ + indexId: "indexId", + }); + const metadata = nodeToMetadata(node); + expect(metadata["_node_type"]).toBe("IndexNode"); + } + { + const node = new ImageNode({ + image: "image", + }); + const metadata = nodeToMetadata(node); + expect(metadata["_node_type"]).toBe("ImageNode"); + } + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0dc87238ce..e2da5993b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -162,7 +162,7 @@ importers: version: link:../packages/llamaindex mongodb: specifier: ^6.7.0 - version: 6.8.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0))) + version: 6.8.0(@aws-sdk/credential-providers@3.637.0) pathe: specifier: ^1.1.2 version: 1.1.2 @@ -380,6 +380,9 @@ importers: bunchee: specifier: 5.3.2 version: 5.3.2(typescript@5.5.4) + change-case: + specifier: ^5.4.4 + version: 5.4.4 natural: specifier: ^8.0.1 version: 8.0.1(@aws-sdk/credential-providers@3.637.0) @@ -567,7 +570,7 @@ importers: version: 2.0.0 mongodb: specifier: ^6.7.0 - version: 6.8.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0))) + version: 6.8.0(@aws-sdk/credential-providers@3.637.0) notion-md-crawler: specifier: ^1.0.0 version: 1.0.0(encoding@0.1.13) @@ -4927,6 +4930,9 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -11920,7 +11926,7 @@ snapshots: '@babel/helpers': 7.25.6 '@babel/parser': 7.25.6 '@babel/template': 7.25.0 - '@babel/traverse': 7.25.6 + '@babel/traverse': 7.23.2 '@babel/types': 7.25.6 convert-source-map: 2.0.0 debug: 4.3.6 @@ -11964,7 +11970,7 @@ snapshots: '@babel/helper-optimise-call-expression': 7.24.7 '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2) '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 - '@babel/traverse': 7.25.6 + '@babel/traverse': 7.23.2 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -12002,7 +12008,7 @@ snapshots: '@babel/helper-member-expression-to-functions@7.24.8': dependencies: - '@babel/traverse': 7.25.6 + '@babel/traverse': 7.23.2 '@babel/types': 7.25.6 transitivePeerDependencies: - supports-color @@ -12035,7 +12041,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-wrap-function': 7.25.0 - '@babel/traverse': 7.25.6 + '@babel/traverse': 7.23.2 transitivePeerDependencies: - supports-color @@ -12044,7 +12050,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-member-expression-to-functions': 7.24.8 '@babel/helper-optimise-call-expression': 7.24.7 - '@babel/traverse': 7.25.6 + '@babel/traverse': 7.23.2 transitivePeerDependencies: - supports-color @@ -12057,7 +12063,7 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.24.7': dependencies: - '@babel/traverse': 7.25.6 + '@babel/traverse': 7.23.2 '@babel/types': 7.25.6 transitivePeerDependencies: - supports-color @@ -16565,6 +16571,8 @@ snapshots: chalk@5.3.0: {} + change-case@5.4.4: {} + char-regex@1.0.2: {} character-entities-html4@2.1.0: {} @@ -17719,16 +17727,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.2(@typescript-eslint/parser@8.3.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.3.0(eslint@8.57.0)(typescript@5.5.4) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.3.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0): dependencies: array-includes: 3.1.8 @@ -17739,7 +17737,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.2(@typescript-eslint/parser@8.3.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.2(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -20467,7 +20465,7 @@ snapshots: optionalDependencies: '@aws-sdk/credential-providers': 3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)) - mongodb@6.8.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0))): + mongodb@6.8.0(@aws-sdk/credential-providers@3.637.0): dependencies: '@mongodb-js/saslprep': 1.1.7 bson: 6.8.0