@wiscale/velesdb-sdk 1.17.0 → 1.18.0

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.
package/dist/index.js CHANGED
@@ -1815,16 +1815,13 @@ async function getEdgeCount(transport, collection) {
1815
1815
  return response.data?.count ?? 0;
1816
1816
  }
1817
1817
  async function listNodes(transport, collection) {
1818
- const response = await transport.requestJson(
1819
- "GET",
1820
- `${collectionPath(collection)}/graph/nodes`
1821
- );
1818
+ const response = await transport.requestJson("GET", `${collectionPath(collection)}/graph/nodes`);
1822
1819
  throwOnError(response, `Collection '${collection}'`);
1823
1820
  const data = response.data;
1824
1821
  return { nodeIds: data.node_ids, count: data.count };
1825
1822
  }
1826
- function idToNumber(id) {
1827
- return typeof id === "string" ? Number(id) : id;
1823
+ function idToGraphId(id) {
1824
+ return id;
1828
1825
  }
1829
1826
  async function getNodeEdges(transport, collection, nodeId, options) {
1830
1827
  const params = new URLSearchParams();
@@ -1835,9 +1832,9 @@ async function getNodeEdges(transport, collection, nodeId, options) {
1835
1832
  const response = await transport.requestJson("GET", url);
1836
1833
  throwOnError(response, `Collection '${collection}'`);
1837
1834
  return (response.data?.edges ?? []).map((e) => ({
1838
- id: idToNumber(e.id),
1839
- source: idToNumber(e.source),
1840
- target: idToNumber(e.target),
1835
+ id: e.id,
1836
+ source: e.source,
1837
+ target: e.target,
1841
1838
  label: e.label,
1842
1839
  properties: e.properties
1843
1840
  }));
@@ -1847,7 +1844,7 @@ async function getNodePayload(transport, collection, nodeId) {
1847
1844
  throwOnError(response, `Collection '${collection}'`);
1848
1845
  const data = response.data;
1849
1846
  return {
1850
- nodeId: idToNumber(data.node_id),
1847
+ nodeId: idToGraphId(data.node_id),
1851
1848
  payload: data.payload
1852
1849
  };
1853
1850
  }
@@ -1871,7 +1868,7 @@ async function graphSearch(transport, collection, request2) {
1871
1868
  throwOnError(response, `Collection '${collection}'`);
1872
1869
  const items = (response.data?.results ?? []).map(
1873
1870
  (r) => ({
1874
- id: idToNumber(r.id),
1871
+ id: idToGraphId(r.id),
1875
1872
  score: r.score,
1876
1873
  payload: r.payload
1877
1874
  })
@@ -1905,9 +1902,11 @@ async function storeSemanticFact(transport, collection, entry) {
1905
1902
  id: entry.id,
1906
1903
  vector: entry.embedding,
1907
1904
  payload: {
1905
+ // Caller metadata is spread first so the reserved keys below
1906
+ // (`_memory_type`, `text`) always win and cannot be clobbered.
1907
+ ...entry.metadata,
1908
1908
  _memory_type: "semantic",
1909
- text: entry.text,
1910
- ...entry.metadata
1909
+ text: entry.text
1911
1910
  }
1912
1911
  }]
1913
1912
  }
@@ -1927,16 +1926,20 @@ async function recordEpisodicEvent(transport, collection, event) {
1927
1926
  id,
1928
1927
  vector: event.embedding,
1929
1928
  payload: {
1929
+ // Caller-supplied data/metadata is spread first so the reserved
1930
+ // keys below (`_memory_type`, `event_type`, `timestamp`) always
1931
+ // win and cannot be clobbered.
1932
+ ...event.data,
1933
+ ...event.metadata,
1930
1934
  _memory_type: "episodic",
1931
1935
  event_type: event.eventType,
1932
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1933
- ...event.data,
1934
- ...event.metadata
1936
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1935
1937
  }
1936
1938
  }]
1937
1939
  }
1938
1940
  );
1939
1941
  throwOnError(response);
1942
+ return id;
1940
1943
  }
1941
1944
  async function recallEpisodicEvents(transport, collection, embedding, k = 5) {
1942
1945
  return transport.searchVectors(collection, embedding, k, { _memory_type: "episodic" });
@@ -1949,16 +1952,21 @@ async function storeProceduralPattern(transport, collection, pattern) {
1949
1952
  {
1950
1953
  points: [{
1951
1954
  id,
1955
+ vector: pattern.embedding,
1952
1956
  payload: {
1957
+ // Caller metadata is spread first so the reserved keys below
1958
+ // (`_memory_type`, `name`, `steps`) always win and cannot be
1959
+ // clobbered.
1960
+ ...pattern.metadata,
1953
1961
  _memory_type: "procedural",
1954
1962
  name: pattern.name,
1955
- steps: pattern.steps,
1956
- ...pattern.metadata
1963
+ steps: pattern.steps
1957
1964
  }
1958
1965
  }]
1959
1966
  }
1960
1967
  );
1961
1968
  throwOnError(response);
1969
+ return id;
1962
1970
  }
1963
1971
  async function matchProceduralPatterns(transport, collection, embedding, k = 5) {
1964
1972
  return transport.searchVectors(collection, embedding, k, { _memory_type: "procedural" });
@@ -2112,15 +2120,29 @@ async function addEdge(transport, collection, edge) {
2112
2120
  throwOnError(response, `Collection '${collection}'`);
2113
2121
  }
2114
2122
  function toGraphEdge(e) {
2115
- const toNum = (v) => typeof v === "string" ? Number(v) : v;
2116
2123
  return {
2117
- id: toNum(e.id),
2118
- source: toNum(e.source),
2119
- target: toNum(e.target),
2124
+ id: e.id,
2125
+ source: e.source,
2126
+ target: e.target,
2120
2127
  label: e.label,
2121
2128
  properties: e.properties
2122
2129
  };
2123
2130
  }
2131
+ function toTraverseResponse(data) {
2132
+ return {
2133
+ results: data.results.map((r) => ({
2134
+ targetId: r.target_id,
2135
+ depth: r.depth,
2136
+ path: r.path
2137
+ })),
2138
+ nextCursor: data.next_cursor ?? void 0,
2139
+ hasMore: data.has_more,
2140
+ stats: {
2141
+ visited: data.stats.visited,
2142
+ depthReached: data.stats.depth_reached
2143
+ }
2144
+ };
2145
+ }
2124
2146
  async function getEdges(transport, collection, options) {
2125
2147
  const queryParams = options?.label ? `?label=${encodeURIComponent(options.label)}` : "";
2126
2148
  const response = await transport.requestJson(
@@ -2144,20 +2166,7 @@ async function traverseGraph(transport, collection, request2) {
2144
2166
  }
2145
2167
  );
2146
2168
  throwOnError(response, `Collection '${collection}'`);
2147
- const data = response.data;
2148
- return {
2149
- results: data.results.map((r) => ({
2150
- targetId: r.target_id,
2151
- depth: r.depth,
2152
- path: r.path
2153
- })),
2154
- nextCursor: data.next_cursor ?? void 0,
2155
- hasMore: data.has_more,
2156
- stats: {
2157
- visited: data.stats.visited,
2158
- depthReached: data.stats.depth_reached
2159
- }
2160
- };
2169
+ return toTraverseResponse(response.data);
2161
2170
  }
2162
2171
  async function getNodeDegree(transport, collection, nodeId) {
2163
2172
  const response = await transport.requestJson(
@@ -2192,20 +2201,7 @@ async function traverseParallel(transport, collection, request2) {
2192
2201
  }
2193
2202
  );
2194
2203
  throwOnError(response, `Collection '${collection}'`);
2195
- const data = response.data;
2196
- return {
2197
- results: data.results.map((r) => ({
2198
- targetId: r.target_id,
2199
- depth: r.depth,
2200
- path: r.path
2201
- })),
2202
- nextCursor: data.next_cursor ?? void 0,
2203
- hasMore: data.has_more,
2204
- stats: {
2205
- visited: data.stats.visited,
2206
- depthReached: data.stats.depth_reached
2207
- }
2208
- };
2204
+ return toTraverseResponse(response.data);
2209
2205
  }
2210
2206
 
2211
2207
  // src/backends/query-backend.ts
@@ -2890,7 +2886,16 @@ var AgentMemoryClient = class {
2890
2886
  this.backend = backend;
2891
2887
  this.config = config;
2892
2888
  }
2893
- /** Configured embedding dimension (default: 384) */
2889
+ /**
2890
+ * Advisory embedding dimension passed at construction (default: 384).
2891
+ *
2892
+ * This value is **not** enforced and does not create or size any
2893
+ * collection — the dimension that actually governs storage and search
2894
+ * is the one fixed when the collection was created
2895
+ * (`db.createCollection(name, { dimension, metric: 'cosine' })`).
2896
+ * Embeddings you pass to `storeFact` / `recordEvent` / `learnProcedure`
2897
+ * must match that collection dimension.
2898
+ */
2894
2899
  get dimension() {
2895
2900
  return this.config?.dimension ?? 384;
2896
2901
  }
@@ -2902,7 +2907,7 @@ var AgentMemoryClient = class {
2902
2907
  async searchFacts(collection, embedding, k = 5) {
2903
2908
  return this.backend.searchSemanticMemory(collection, embedding, k);
2904
2909
  }
2905
- /** Record an episodic event */
2910
+ /** Record an episodic event. Returns the generated point ID. */
2906
2911
  async recordEvent(collection, event) {
2907
2912
  return this.backend.recordEpisodicEvent(collection, event);
2908
2913
  }
@@ -2910,7 +2915,7 @@ var AgentMemoryClient = class {
2910
2915
  async recallEvents(collection, embedding, k = 5) {
2911
2916
  return this.backend.recallEpisodicEvents(collection, embedding, k);
2912
2917
  }
2913
- /** Store a procedural pattern */
2918
+ /** Store a procedural pattern. Returns the generated point ID. */
2914
2919
  async learnProcedure(collection, pattern) {
2915
2920
  return this.backend.storeProceduralPattern(collection, pattern);
2916
2921
  }
@@ -2918,6 +2923,10 @@ var AgentMemoryClient = class {
2918
2923
  async recallProcedures(collection, embedding, k = 5) {
2919
2924
  return this.backend.matchProceduralPatterns(collection, embedding, k);
2920
2925
  }
2926
+ /** Delete a memory entry (fact, event, or procedure) by its point ID. */
2927
+ async deleteMemory(collection, id) {
2928
+ return this.backend.delete(collection, id);
2929
+ }
2921
2930
  };
2922
2931
 
2923
2932
  // src/client/validation.ts
@@ -3057,12 +3066,15 @@ function aggregate2(backend, queryString, params, options) {
3057
3066
  }
3058
3067
 
3059
3068
  // src/client/graph-methods.ts
3069
+ function isGraphNodeId(value) {
3070
+ return typeof value === "number" || typeof value === "string";
3071
+ }
3060
3072
  function addEdge2(backend, collection, edge) {
3061
3073
  if (!edge.label || typeof edge.label !== "string") {
3062
3074
  throw new ValidationError("Edge label is required and must be a string");
3063
3075
  }
3064
- if (typeof edge.source !== "number" || typeof edge.target !== "number") {
3065
- throw new ValidationError("Edge source and target must be numbers");
3076
+ if (!isGraphNodeId(edge.source) || !isGraphNodeId(edge.target)) {
3077
+ throw new ValidationError("Edge source and target must be numbers or strings");
3066
3078
  }
3067
3079
  return backend.addEdge(collection, edge);
3068
3080
  }
@@ -3070,8 +3082,8 @@ function getEdges2(backend, collection, options) {
3070
3082
  return backend.getEdges(collection, options);
3071
3083
  }
3072
3084
  function traverseGraph2(backend, collection, request2) {
3073
- if (typeof request2.source !== "number") {
3074
- throw new ValidationError("Source node ID must be a number");
3085
+ if (!isGraphNodeId(request2.source)) {
3086
+ throw new ValidationError("Source node ID must be a number or string");
3075
3087
  }
3076
3088
  if (request2.strategy && !["bfs", "dfs"].includes(request2.strategy)) {
3077
3089
  throw new ValidationError("Strategy must be 'bfs' or 'dfs'");
@@ -3082,6 +3094,9 @@ function traverseParallel2(backend, collection, request2) {
3082
3094
  if (!Array.isArray(request2.sources) || request2.sources.length === 0) {
3083
3095
  throw new ValidationError("At least one source node ID is required");
3084
3096
  }
3097
+ if (!request2.sources.every(isGraphNodeId)) {
3098
+ throw new ValidationError("Source node IDs must be numbers or strings");
3099
+ }
3085
3100
  return backend.traverseParallel(collection, request2);
3086
3101
  }
3087
3102
  function getNodeDegree2(backend, collection, nodeId) {
package/dist/index.mjs CHANGED
@@ -1676,16 +1676,13 @@ async function getEdgeCount(transport, collection) {
1676
1676
  return response.data?.count ?? 0;
1677
1677
  }
1678
1678
  async function listNodes(transport, collection) {
1679
- const response = await transport.requestJson(
1680
- "GET",
1681
- `${collectionPath(collection)}/graph/nodes`
1682
- );
1679
+ const response = await transport.requestJson("GET", `${collectionPath(collection)}/graph/nodes`);
1683
1680
  throwOnError(response, `Collection '${collection}'`);
1684
1681
  const data = response.data;
1685
1682
  return { nodeIds: data.node_ids, count: data.count };
1686
1683
  }
1687
- function idToNumber(id) {
1688
- return typeof id === "string" ? Number(id) : id;
1684
+ function idToGraphId(id) {
1685
+ return id;
1689
1686
  }
1690
1687
  async function getNodeEdges(transport, collection, nodeId, options) {
1691
1688
  const params = new URLSearchParams();
@@ -1696,9 +1693,9 @@ async function getNodeEdges(transport, collection, nodeId, options) {
1696
1693
  const response = await transport.requestJson("GET", url);
1697
1694
  throwOnError(response, `Collection '${collection}'`);
1698
1695
  return (response.data?.edges ?? []).map((e) => ({
1699
- id: idToNumber(e.id),
1700
- source: idToNumber(e.source),
1701
- target: idToNumber(e.target),
1696
+ id: e.id,
1697
+ source: e.source,
1698
+ target: e.target,
1702
1699
  label: e.label,
1703
1700
  properties: e.properties
1704
1701
  }));
@@ -1708,7 +1705,7 @@ async function getNodePayload(transport, collection, nodeId) {
1708
1705
  throwOnError(response, `Collection '${collection}'`);
1709
1706
  const data = response.data;
1710
1707
  return {
1711
- nodeId: idToNumber(data.node_id),
1708
+ nodeId: idToGraphId(data.node_id),
1712
1709
  payload: data.payload
1713
1710
  };
1714
1711
  }
@@ -1732,7 +1729,7 @@ async function graphSearch(transport, collection, request2) {
1732
1729
  throwOnError(response, `Collection '${collection}'`);
1733
1730
  const items = (response.data?.results ?? []).map(
1734
1731
  (r) => ({
1735
- id: idToNumber(r.id),
1732
+ id: idToGraphId(r.id),
1736
1733
  score: r.score,
1737
1734
  payload: r.payload
1738
1735
  })
@@ -1766,9 +1763,11 @@ async function storeSemanticFact(transport, collection, entry) {
1766
1763
  id: entry.id,
1767
1764
  vector: entry.embedding,
1768
1765
  payload: {
1766
+ // Caller metadata is spread first so the reserved keys below
1767
+ // (`_memory_type`, `text`) always win and cannot be clobbered.
1768
+ ...entry.metadata,
1769
1769
  _memory_type: "semantic",
1770
- text: entry.text,
1771
- ...entry.metadata
1770
+ text: entry.text
1772
1771
  }
1773
1772
  }]
1774
1773
  }
@@ -1788,16 +1787,20 @@ async function recordEpisodicEvent(transport, collection, event) {
1788
1787
  id,
1789
1788
  vector: event.embedding,
1790
1789
  payload: {
1790
+ // Caller-supplied data/metadata is spread first so the reserved
1791
+ // keys below (`_memory_type`, `event_type`, `timestamp`) always
1792
+ // win and cannot be clobbered.
1793
+ ...event.data,
1794
+ ...event.metadata,
1791
1795
  _memory_type: "episodic",
1792
1796
  event_type: event.eventType,
1793
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1794
- ...event.data,
1795
- ...event.metadata
1797
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1796
1798
  }
1797
1799
  }]
1798
1800
  }
1799
1801
  );
1800
1802
  throwOnError(response);
1803
+ return id;
1801
1804
  }
1802
1805
  async function recallEpisodicEvents(transport, collection, embedding, k = 5) {
1803
1806
  return transport.searchVectors(collection, embedding, k, { _memory_type: "episodic" });
@@ -1810,16 +1813,21 @@ async function storeProceduralPattern(transport, collection, pattern) {
1810
1813
  {
1811
1814
  points: [{
1812
1815
  id,
1816
+ vector: pattern.embedding,
1813
1817
  payload: {
1818
+ // Caller metadata is spread first so the reserved keys below
1819
+ // (`_memory_type`, `name`, `steps`) always win and cannot be
1820
+ // clobbered.
1821
+ ...pattern.metadata,
1814
1822
  _memory_type: "procedural",
1815
1823
  name: pattern.name,
1816
- steps: pattern.steps,
1817
- ...pattern.metadata
1824
+ steps: pattern.steps
1818
1825
  }
1819
1826
  }]
1820
1827
  }
1821
1828
  );
1822
1829
  throwOnError(response);
1830
+ return id;
1823
1831
  }
1824
1832
  async function matchProceduralPatterns(transport, collection, embedding, k = 5) {
1825
1833
  return transport.searchVectors(collection, embedding, k, { _memory_type: "procedural" });
@@ -1973,15 +1981,29 @@ async function addEdge(transport, collection, edge) {
1973
1981
  throwOnError(response, `Collection '${collection}'`);
1974
1982
  }
1975
1983
  function toGraphEdge(e) {
1976
- const toNum = (v) => typeof v === "string" ? Number(v) : v;
1977
1984
  return {
1978
- id: toNum(e.id),
1979
- source: toNum(e.source),
1980
- target: toNum(e.target),
1985
+ id: e.id,
1986
+ source: e.source,
1987
+ target: e.target,
1981
1988
  label: e.label,
1982
1989
  properties: e.properties
1983
1990
  };
1984
1991
  }
1992
+ function toTraverseResponse(data) {
1993
+ return {
1994
+ results: data.results.map((r) => ({
1995
+ targetId: r.target_id,
1996
+ depth: r.depth,
1997
+ path: r.path
1998
+ })),
1999
+ nextCursor: data.next_cursor ?? void 0,
2000
+ hasMore: data.has_more,
2001
+ stats: {
2002
+ visited: data.stats.visited,
2003
+ depthReached: data.stats.depth_reached
2004
+ }
2005
+ };
2006
+ }
1985
2007
  async function getEdges(transport, collection, options) {
1986
2008
  const queryParams = options?.label ? `?label=${encodeURIComponent(options.label)}` : "";
1987
2009
  const response = await transport.requestJson(
@@ -2005,20 +2027,7 @@ async function traverseGraph(transport, collection, request2) {
2005
2027
  }
2006
2028
  );
2007
2029
  throwOnError(response, `Collection '${collection}'`);
2008
- const data = response.data;
2009
- return {
2010
- results: data.results.map((r) => ({
2011
- targetId: r.target_id,
2012
- depth: r.depth,
2013
- path: r.path
2014
- })),
2015
- nextCursor: data.next_cursor ?? void 0,
2016
- hasMore: data.has_more,
2017
- stats: {
2018
- visited: data.stats.visited,
2019
- depthReached: data.stats.depth_reached
2020
- }
2021
- };
2030
+ return toTraverseResponse(response.data);
2022
2031
  }
2023
2032
  async function getNodeDegree(transport, collection, nodeId) {
2024
2033
  const response = await transport.requestJson(
@@ -2053,20 +2062,7 @@ async function traverseParallel(transport, collection, request2) {
2053
2062
  }
2054
2063
  );
2055
2064
  throwOnError(response, `Collection '${collection}'`);
2056
- const data = response.data;
2057
- return {
2058
- results: data.results.map((r) => ({
2059
- targetId: r.target_id,
2060
- depth: r.depth,
2061
- path: r.path
2062
- })),
2063
- nextCursor: data.next_cursor ?? void 0,
2064
- hasMore: data.has_more,
2065
- stats: {
2066
- visited: data.stats.visited,
2067
- depthReached: data.stats.depth_reached
2068
- }
2069
- };
2065
+ return toTraverseResponse(response.data);
2070
2066
  }
2071
2067
 
2072
2068
  // src/backends/query-backend.ts
@@ -2751,7 +2747,16 @@ var AgentMemoryClient = class {
2751
2747
  this.backend = backend;
2752
2748
  this.config = config;
2753
2749
  }
2754
- /** Configured embedding dimension (default: 384) */
2750
+ /**
2751
+ * Advisory embedding dimension passed at construction (default: 384).
2752
+ *
2753
+ * This value is **not** enforced and does not create or size any
2754
+ * collection — the dimension that actually governs storage and search
2755
+ * is the one fixed when the collection was created
2756
+ * (`db.createCollection(name, { dimension, metric: 'cosine' })`).
2757
+ * Embeddings you pass to `storeFact` / `recordEvent` / `learnProcedure`
2758
+ * must match that collection dimension.
2759
+ */
2755
2760
  get dimension() {
2756
2761
  return this.config?.dimension ?? 384;
2757
2762
  }
@@ -2763,7 +2768,7 @@ var AgentMemoryClient = class {
2763
2768
  async searchFacts(collection, embedding, k = 5) {
2764
2769
  return this.backend.searchSemanticMemory(collection, embedding, k);
2765
2770
  }
2766
- /** Record an episodic event */
2771
+ /** Record an episodic event. Returns the generated point ID. */
2767
2772
  async recordEvent(collection, event) {
2768
2773
  return this.backend.recordEpisodicEvent(collection, event);
2769
2774
  }
@@ -2771,7 +2776,7 @@ var AgentMemoryClient = class {
2771
2776
  async recallEvents(collection, embedding, k = 5) {
2772
2777
  return this.backend.recallEpisodicEvents(collection, embedding, k);
2773
2778
  }
2774
- /** Store a procedural pattern */
2779
+ /** Store a procedural pattern. Returns the generated point ID. */
2775
2780
  async learnProcedure(collection, pattern) {
2776
2781
  return this.backend.storeProceduralPattern(collection, pattern);
2777
2782
  }
@@ -2779,6 +2784,10 @@ var AgentMemoryClient = class {
2779
2784
  async recallProcedures(collection, embedding, k = 5) {
2780
2785
  return this.backend.matchProceduralPatterns(collection, embedding, k);
2781
2786
  }
2787
+ /** Delete a memory entry (fact, event, or procedure) by its point ID. */
2788
+ async deleteMemory(collection, id) {
2789
+ return this.backend.delete(collection, id);
2790
+ }
2782
2791
  };
2783
2792
 
2784
2793
  // src/client/validation.ts
@@ -2918,12 +2927,15 @@ function aggregate2(backend, queryString, params, options) {
2918
2927
  }
2919
2928
 
2920
2929
  // src/client/graph-methods.ts
2930
+ function isGraphNodeId(value) {
2931
+ return typeof value === "number" || typeof value === "string";
2932
+ }
2921
2933
  function addEdge2(backend, collection, edge) {
2922
2934
  if (!edge.label || typeof edge.label !== "string") {
2923
2935
  throw new ValidationError("Edge label is required and must be a string");
2924
2936
  }
2925
- if (typeof edge.source !== "number" || typeof edge.target !== "number") {
2926
- throw new ValidationError("Edge source and target must be numbers");
2937
+ if (!isGraphNodeId(edge.source) || !isGraphNodeId(edge.target)) {
2938
+ throw new ValidationError("Edge source and target must be numbers or strings");
2927
2939
  }
2928
2940
  return backend.addEdge(collection, edge);
2929
2941
  }
@@ -2931,8 +2943,8 @@ function getEdges2(backend, collection, options) {
2931
2943
  return backend.getEdges(collection, options);
2932
2944
  }
2933
2945
  function traverseGraph2(backend, collection, request2) {
2934
- if (typeof request2.source !== "number") {
2935
- throw new ValidationError("Source node ID must be a number");
2946
+ if (!isGraphNodeId(request2.source)) {
2947
+ throw new ValidationError("Source node ID must be a number or string");
2936
2948
  }
2937
2949
  if (request2.strategy && !["bfs", "dfs"].includes(request2.strategy)) {
2938
2950
  throw new ValidationError("Strategy must be 'bfs' or 'dfs'");
@@ -2943,6 +2955,9 @@ function traverseParallel2(backend, collection, request2) {
2943
2955
  if (!Array.isArray(request2.sources) || request2.sources.length === 0) {
2944
2956
  throw new ValidationError("At least one source node ID is required");
2945
2957
  }
2958
+ if (!request2.sources.every(isGraphNodeId)) {
2959
+ throw new ValidationError("Source node IDs must be numbers or strings");
2960
+ }
2946
2961
  return backend.traverseParallel(collection, request2);
2947
2962
  }
2948
2963
  function getNodeDegree2(backend, collection, nodeId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wiscale/velesdb-sdk",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "VelesDB TypeScript SDK: The Local Vector Database for AI & RAG. Microsecond semantic search in Browser & Node.js.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -14,7 +14,8 @@
14
14
  },
15
15
  "files": [
16
16
  "dist",
17
- "README.md"
17
+ "README.md",
18
+ "LICENSE"
18
19
  ],
19
20
  "scripts": {
20
21
  "build": "tsup src/index.ts --format cjs,esm --dts",
@@ -43,7 +44,7 @@
43
44
  "llm"
44
45
  ],
45
46
  "author": "Wiscale France",
46
- "license": "MIT",
47
+ "license": "SEE LICENSE IN LICENSE",
47
48
  "repository": {
48
49
  "type": "git",
49
50
  "url": "https://github.com/cyberlife-coder/VelesDB.git",