@synapcores/sdk 0.2.1 → 0.4.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.mjs CHANGED
@@ -254,20 +254,20 @@ var Collection = class {
254
254
  }
255
255
  async vectorSearch(options) {
256
256
  const { data } = await this.client._getHttpClient().post(
257
- `${this.basePath}/vector_search`,
257
+ `/vectors/collections/${this.name}/search`,
258
258
  {
259
259
  vector: options.vector,
260
- field: options.field || "embedding",
261
- top_k: options.topK || 10,
260
+ k: options.topK || 10,
262
261
  filter: options.filter,
263
- distance_metric: options.distanceMetric || "cosine",
264
- include_metadata: options.includeMetadata
262
+ include_metadata: options.includeMetadata !== false
265
263
  }
266
264
  );
265
+ const inner = data?.data ?? data;
266
+ const matches = Array.isArray(inner) ? inner : inner?.matches ?? inner?.results ?? inner?.documents ?? data?.matches ?? data?.results ?? data?.documents ?? [];
267
267
  return {
268
- documents: data.documents,
269
- total: data.total,
270
- tookMs: data.took_ms
268
+ documents: matches,
269
+ total: (inner && !Array.isArray(inner) ? inner.total : void 0) ?? matches.length,
270
+ tookMs: (inner && !Array.isArray(inner) ? inner.took_ms : void 0) ?? data?.took_ms
271
271
  };
272
272
  }
273
273
  async query(options = {}) {
@@ -332,6 +332,125 @@ var Collection = class {
332
332
  }
333
333
  };
334
334
 
335
+ // src/vector_collection.ts
336
+ var VectorCollection = class {
337
+ constructor(client, name) {
338
+ this.client = client;
339
+ this.name = name;
340
+ }
341
+ get basePath() {
342
+ return `/vectors/collections/${encodeURIComponent(this.name)}`;
343
+ }
344
+ /**
345
+ * Insert one or more vectors.
346
+ *
347
+ * Wire: `POST /v1/vectors/collections/{name}/vectors` with
348
+ * `{ vectors: [{ id, values, metadata }] }`.
349
+ *
350
+ * Accepts either a single record or an array — the SDK always sends
351
+ * the wrapped `{ vectors: [...] }` envelope the gateway expects.
352
+ */
353
+ async insert(records) {
354
+ const vectors = Array.isArray(records) ? records : [records];
355
+ const { data } = await this.client._getHttpClient().post(
356
+ `${this.basePath}/vectors`,
357
+ { vectors }
358
+ );
359
+ return data?.data ?? data;
360
+ }
361
+ /**
362
+ * k-NN search over the vector collection.
363
+ *
364
+ * Wire: `POST /v1/vectors/collections/{name}/search` with
365
+ * `{ vector, k, include_metadata, filter? }`.
366
+ *
367
+ * Returns the bare array of hits — gateway envelope (`{data: [...]}`) is
368
+ * unwrapped automatically for parity with `Collection.vectorSearch`.
369
+ */
370
+ async search(options) {
371
+ const k = options.k ?? options.topK ?? 10;
372
+ const body = {
373
+ vector: options.vector,
374
+ k,
375
+ include_metadata: options.includeMetadata !== false
376
+ };
377
+ if (options.filter !== void 0) body.filter = options.filter;
378
+ const { data } = await this.client._getHttpClient().post(
379
+ `${this.basePath}/search`,
380
+ body
381
+ );
382
+ const inner = data?.data ?? data;
383
+ if (Array.isArray(inner)) return inner;
384
+ return inner?.matches ?? inner?.results ?? inner?.hits ?? [];
385
+ }
386
+ /**
387
+ * Fetch a single vector by id.
388
+ *
389
+ * Wire: `GET /v1/vectors/collections/{name}/vectors/{id}`. Returns the
390
+ * gateway payload `{ id, values, metadata }` (envelope unwrapped) or
391
+ * `null` on 404.
392
+ */
393
+ async get(id) {
394
+ try {
395
+ const { data } = await this.client._getHttpClient().get(
396
+ `${this.basePath}/vectors/${encodeURIComponent(id)}`
397
+ );
398
+ return data?.data ?? data;
399
+ } catch (err) {
400
+ if (err?.code === "NOT_FOUND" || err?.status === 404) return null;
401
+ throw err;
402
+ }
403
+ }
404
+ /**
405
+ * Delete one or more vectors by id.
406
+ *
407
+ * Single-id wire: `DELETE /v1/vectors/collections/{name}/vectors/{id}`.
408
+ * Bulk wire: `DELETE /v1/vectors/collections/{name}/vectors` with
409
+ * `{ ids: [...] }` body.
410
+ */
411
+ async delete(ids) {
412
+ if (typeof ids === "string") {
413
+ const { data: data2 } = await this.client._getHttpClient().delete(
414
+ `${this.basePath}/vectors/${encodeURIComponent(ids)}`
415
+ );
416
+ return data2?.data ?? data2;
417
+ }
418
+ const { data } = await this.client._getHttpClient().request({
419
+ method: "DELETE",
420
+ url: `${this.basePath}/vectors`,
421
+ data: { ids }
422
+ });
423
+ return data?.data ?? data;
424
+ }
425
+ /**
426
+ * Vector count.
427
+ *
428
+ * Wire: `GET /v1/vectors/collections/{name}/count` if the gateway
429
+ * exposes it, otherwise falls back to `info().vector_count`.
430
+ */
431
+ async count() {
432
+ try {
433
+ const { data } = await this.client._getHttpClient().get(`${this.basePath}/count`);
434
+ const inner = data?.data ?? data;
435
+ const n = typeof inner === "number" ? inner : inner?.count ?? inner?.vector_count;
436
+ if (typeof n === "number") return n;
437
+ } catch {
438
+ }
439
+ const info = await this.info();
440
+ return typeof info?.vector_count === "number" ? info.vector_count : 0;
441
+ }
442
+ /**
443
+ * Collection metadata.
444
+ *
445
+ * Wire: `GET /v1/vectors/collections/{name}` returning
446
+ * `{ name, dimensions, vector_count, distance_metric, index_type }`.
447
+ */
448
+ async info() {
449
+ const { data } = await this.client._getHttpClient().get(this.basePath);
450
+ return data?.data ?? data;
451
+ }
452
+ };
453
+
335
454
  // src/automl.ts
336
455
  var AutoMLModel = class {
337
456
  constructor(client, info) {
@@ -405,27 +524,48 @@ var AutoMLClient = class {
405
524
  return new AutoMLModel(this, modelInfo);
406
525
  }
407
526
  async getModel(modelId) {
408
- const { data } = await this.synapCores._getHttpClient().get(
409
- `/automl/models/${modelId}`
410
- );
411
- const modelInfo = {
412
- id: data.id,
413
- name: data.name,
414
- task: data.task,
415
- status: data.status,
416
- accuracy: data.accuracy,
417
- createdAt: new Date(data.created_at ?? Date.now()),
418
- updatedAt: data.updated_at ? new Date(data.updated_at) : void 0,
419
- config: data.config ?? {}
420
- };
421
- return new AutoMLModel(this, modelInfo);
527
+ try {
528
+ const { data } = await this.synapCores._getHttpClient().get(
529
+ `/automl/models/${modelId}`
530
+ );
531
+ const m = data?.data ?? data;
532
+ const modelInfo = {
533
+ id: m.id ?? modelId,
534
+ name: m.name ?? modelId,
535
+ task: m.task,
536
+ status: m.status,
537
+ accuracy: m.accuracy,
538
+ createdAt: new Date(m.created_at ?? Date.now()),
539
+ updatedAt: m.updated_at ? new Date(m.updated_at) : void 0,
540
+ config: m.config ?? {}
541
+ };
542
+ return new AutoMLModel(this, modelInfo);
543
+ } catch (err) {
544
+ const status = err?.statusCode ?? err?.response?.status;
545
+ const code = err?.code;
546
+ if (status === 404 || code === "NOT_FOUND") {
547
+ const modelInfo = {
548
+ id: modelId,
549
+ name: modelId,
550
+ task: void 0,
551
+ status: "unknown",
552
+ accuracy: void 0,
553
+ createdAt: /* @__PURE__ */ new Date(),
554
+ updatedAt: void 0,
555
+ config: {}
556
+ };
557
+ return new AutoMLModel(this, modelInfo);
558
+ }
559
+ throw err;
560
+ }
422
561
  }
423
562
  async listModels(filters) {
424
563
  const { data } = await this.synapCores._getHttpClient().get("/automl/models", {
425
564
  params: filters
426
565
  });
427
- return (data.models ?? data ?? []).map((model) => ({
428
- id: model.id,
566
+ const list = Array.isArray(data) ? data : Array.isArray(data?.data) ? data.data : Array.isArray(data?.models) ? data.models : Array.isArray(data?.data?.items) ? data.data.items : [];
567
+ return list.map((model) => ({
568
+ id: model.id ?? model.name,
429
569
  name: model.name,
430
570
  task: model.task,
431
571
  status: model.status,
@@ -1936,23 +2076,24 @@ var GraphsApi = class {
1936
2076
  constructor(synapCores) {
1937
2077
  this.synapCores = synapCores;
1938
2078
  }
2079
+ // v0.3.0: gateway routes live under /graph/graphs, not /graphs.
1939
2080
  async list() {
1940
- const { data } = await this.synapCores._getHttpClient().get("/graphs");
2081
+ const { data } = await this.synapCores._getHttpClient().get("/graph/graphs");
1941
2082
  return (data.graphs ?? data ?? []).map((g) => this.normalize(g));
1942
2083
  }
1943
2084
  async create(name, opts = {}) {
1944
- const { data } = await this.synapCores._getHttpClient().post("/graphs", {
2085
+ const { data } = await this.synapCores._getHttpClient().post("/graph/graphs", {
1945
2086
  name,
1946
2087
  description: opts.description
1947
2088
  });
1948
2089
  return this.normalize(data);
1949
2090
  }
1950
2091
  async get(name) {
1951
- const { data } = await this.synapCores._getHttpClient().get(`/graphs/${name}`);
2092
+ const { data } = await this.synapCores._getHttpClient().get(`/graph/graphs/${name}`);
1952
2093
  return this.normalize(data);
1953
2094
  }
1954
2095
  async delete(name) {
1955
- await this.synapCores._getHttpClient().delete(`/graphs/${name}`);
2096
+ await this.synapCores._getHttpClient().delete(`/graph/graphs/${name}`);
1956
2097
  }
1957
2098
  normalize(data) {
1958
2099
  return {
@@ -2751,6 +2892,20 @@ var SynapCores = class {
2751
2892
  this.collectionsCache = /* @__PURE__ */ new Map();
2752
2893
  this.currentTransaction = null;
2753
2894
  this.preparedStatements = /* @__PURE__ */ new Map();
2895
+ // =================================================================
2896
+ // VECTOR COLLECTIONS — /v1/vectors/collections/{name}
2897
+ //
2898
+ // The gateway exposes two parallel "collection" worlds:
2899
+ // (a) document-store collections under /v1/collections (above), and
2900
+ // (b) vector collections under /v1/vectors/collections (below).
2901
+ //
2902
+ // v0.3.0 only wrapped (a) so vector-first users had to drop down to
2903
+ // `_getHttpClient()` to call (b) directly. v0.4.0 adds first-class
2904
+ // helpers — `createVectorCollection`, `vectorCollection(name)`,
2905
+ // `listVectorCollections`, `deleteVectorCollection` — that target (b)
2906
+ // and return a typed `VectorCollection` handle.
2907
+ // =================================================================
2908
+ this.vectorCollectionsCache = /* @__PURE__ */ new Map();
2754
2909
  this.config = {
2755
2910
  host: config.host || "localhost",
2756
2911
  port: config.port || 8080,
@@ -2773,14 +2928,14 @@ var SynapCores = class {
2773
2928
  if (this.config.jwtToken) {
2774
2929
  authHeader["Authorization"] = `Bearer ${this.config.jwtToken}`;
2775
2930
  } else if (this.config.apiKey) {
2776
- authHeader["X-API-Key"] = this.config.apiKey;
2931
+ authHeader["Authorization"] = `Bearer ${this.config.apiKey}`;
2777
2932
  }
2778
2933
  this.httpClient = axios.create({
2779
2934
  baseURL,
2780
2935
  timeout: this.config.timeout,
2781
2936
  headers: {
2782
2937
  "Content-Type": "application/json",
2783
- "User-Agent": "synapcores-nodejs/0.2.0",
2938
+ "User-Agent": "synapcores-nodejs/0.4.0",
2784
2939
  ...authHeader
2785
2940
  },
2786
2941
  ...httpsAgent && { httpsAgent }
@@ -2946,15 +3101,35 @@ var SynapCores = class {
2946
3101
  this.collectionsCache.set(name, collection);
2947
3102
  return collection;
2948
3103
  }
3104
+ /**
3105
+ * Synchronous accessor that returns a Collection handle without round-tripping
3106
+ * to the gateway. Use this when you already know the collection exists and just
3107
+ * want to issue a vectorSearch / search / insert against it.
3108
+ *
3109
+ * v0.3.0: added so `client.collection(name).vectorSearch(...)` works without
3110
+ * a preceding await on getCollection().
3111
+ */
3112
+ collection(name) {
3113
+ if (this.collectionsCache.has(name)) {
3114
+ return this.collectionsCache.get(name);
3115
+ }
3116
+ const c = new Collection(this, name);
3117
+ this.collectionsCache.set(name, c);
3118
+ return c;
3119
+ }
2949
3120
  /**
2950
3121
  * List collections (legacy method for backward compatibility)
2951
3122
  */
2952
3123
  async listCollections() {
2953
3124
  const result = await this.listCollectionsDetailed();
2954
- return result.collections.map((c) => c.name);
3125
+ return (result.collections ?? []).map((c) => c.name);
2955
3126
  }
2956
3127
  /**
2957
3128
  * List collections with detailed information matching the database integration guide format
3129
+ *
3130
+ * v0.3.0: gateway returns an envelope { data: { items, total, page, page_size, ... }, meta }.
3131
+ * We normalise that into the SDK's { collections, total, page, pageSize } shape and also
3132
+ * accept legacy { collections: [...] } / bare arrays for forward-compat.
2958
3133
  */
2959
3134
  async listCollectionsDetailed(options) {
2960
3135
  const params = new URLSearchParams();
@@ -2966,7 +3141,14 @@ var SynapCores = class {
2966
3141
  const { data } = await this.httpClient.get(
2967
3142
  `/collections${params.toString() ? `?${params.toString()}` : ""}`
2968
3143
  );
2969
- return data;
3144
+ const inner = data?.data ?? data;
3145
+ const items = Array.isArray(inner) ? inner : inner?.items ?? inner?.collections ?? [];
3146
+ return {
3147
+ collections: items,
3148
+ total: inner?.total ?? items.length,
3149
+ page: inner?.page ?? 1,
3150
+ pageSize: inner?.page_size ?? inner?.pageSize ?? items.length
3151
+ };
2970
3152
  }
2971
3153
  async getDocuments(collectionName, page, pageSize) {
2972
3154
  const { data } = await this.httpClient.get(
@@ -2978,6 +3160,67 @@ var SynapCores = class {
2978
3160
  await this.httpClient.delete(`/collections/${name}`);
2979
3161
  this.collectionsCache.delete(name);
2980
3162
  }
3163
+ /**
3164
+ * Create a vector collection.
3165
+ *
3166
+ * Wire: `POST /v1/vectors/collections` with
3167
+ * `{ name, dimensions, distance_metric }`. Distinct from
3168
+ * `createCollection`, which targets the document-store subsystem.
3169
+ *
3170
+ * @example
3171
+ * const coll = await client.createVectorCollection({
3172
+ * name: 'memory_v1', dimensions: 1536, distance_metric: 'cosine',
3173
+ * });
3174
+ * await coll.insert({ id: 'v1', values: [...], metadata: { ... } });
3175
+ */
3176
+ async createVectorCollection(options) {
3177
+ await this.httpClient.post("/vectors/collections", {
3178
+ name: options.name,
3179
+ dimensions: options.dimensions,
3180
+ distance_metric: options.distance_metric ?? "cosine"
3181
+ });
3182
+ const coll = new VectorCollection(this, options.name);
3183
+ this.vectorCollectionsCache.set(options.name, coll);
3184
+ return coll;
3185
+ }
3186
+ /**
3187
+ * Synchronous accessor for an existing vector collection. Does not
3188
+ * round-trip to the gateway — use `createVectorCollection` if you
3189
+ * need to provision the collection first, or `listVectorCollections`
3190
+ * to confirm existence.
3191
+ *
3192
+ * v0.4.0 split: this targets the **vector subsystem**
3193
+ * (`/v1/vectors/collections/{name}`). `client.collection(name)` still
3194
+ * returns a document-store `Collection` for the legacy subsystem.
3195
+ */
3196
+ vectorCollection(name) {
3197
+ const cached = this.vectorCollectionsCache.get(name);
3198
+ if (cached) return cached;
3199
+ const coll = new VectorCollection(this, name);
3200
+ this.vectorCollectionsCache.set(name, coll);
3201
+ return coll;
3202
+ }
3203
+ /**
3204
+ * List vector collections.
3205
+ *
3206
+ * Wire: `GET /v1/vectors/collections`. Returns the bare array of
3207
+ * collection-info objects (envelope unwrapped).
3208
+ */
3209
+ async listVectorCollections() {
3210
+ const { data } = await this.httpClient.get("/vectors/collections");
3211
+ const inner = data?.data ?? data;
3212
+ if (Array.isArray(inner)) return inner;
3213
+ return inner?.items ?? inner?.collections ?? [];
3214
+ }
3215
+ /**
3216
+ * Delete a vector collection.
3217
+ *
3218
+ * Wire: `DELETE /v1/vectors/collections/{name}`.
3219
+ */
3220
+ async deleteVectorCollection(name) {
3221
+ await this.httpClient.delete(`/vectors/collections/${encodeURIComponent(name)}`);
3222
+ this.vectorCollectionsCache.delete(name);
3223
+ }
2981
3224
  /**
2982
3225
  * Execute SQL query (legacy method for backward compatibility)
2983
3226
  * @deprecated Use executeQuery for new code
@@ -3892,7 +4135,7 @@ var SynapCores = class {
3892
4135
 
3893
4136
  // src/index.ts
3894
4137
  import { z } from "zod";
3895
- var VERSION = "0.2.0";
4138
+ var VERSION = "0.4.0";
3896
4139
  export {
3897
4140
  AuthenticationError,
3898
4141
  AutoMLClient,
@@ -3926,6 +4169,7 @@ export {
3926
4169
  Tx,
3927
4170
  VERSION,
3928
4171
  ValidationError,
4172
+ VectorCollection,
3929
4173
  VectorError,
3930
4174
  z
3931
4175
  };