@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.js CHANGED
@@ -62,6 +62,7 @@ __export(index_exports, {
62
62
  Tx: () => Tx,
63
63
  VERSION: () => VERSION,
64
64
  ValidationError: () => ValidationError,
65
+ VectorCollection: () => VectorCollection,
65
66
  VectorError: () => VectorError,
66
67
  z: () => import_zod.z
67
68
  });
@@ -316,20 +317,20 @@ var Collection = class {
316
317
  }
317
318
  async vectorSearch(options) {
318
319
  const { data } = await this.client._getHttpClient().post(
319
- `${this.basePath}/vector_search`,
320
+ `/vectors/collections/${this.name}/search`,
320
321
  {
321
322
  vector: options.vector,
322
- field: options.field || "embedding",
323
- top_k: options.topK || 10,
323
+ k: options.topK || 10,
324
324
  filter: options.filter,
325
- distance_metric: options.distanceMetric || "cosine",
326
- include_metadata: options.includeMetadata
325
+ include_metadata: options.includeMetadata !== false
327
326
  }
328
327
  );
328
+ const inner = data?.data ?? data;
329
+ const matches = Array.isArray(inner) ? inner : inner?.matches ?? inner?.results ?? inner?.documents ?? data?.matches ?? data?.results ?? data?.documents ?? [];
329
330
  return {
330
- documents: data.documents,
331
- total: data.total,
332
- tookMs: data.took_ms
331
+ documents: matches,
332
+ total: (inner && !Array.isArray(inner) ? inner.total : void 0) ?? matches.length,
333
+ tookMs: (inner && !Array.isArray(inner) ? inner.took_ms : void 0) ?? data?.took_ms
333
334
  };
334
335
  }
335
336
  async query(options = {}) {
@@ -394,6 +395,125 @@ var Collection = class {
394
395
  }
395
396
  };
396
397
 
398
+ // src/vector_collection.ts
399
+ var VectorCollection = class {
400
+ constructor(client, name) {
401
+ this.client = client;
402
+ this.name = name;
403
+ }
404
+ get basePath() {
405
+ return `/vectors/collections/${encodeURIComponent(this.name)}`;
406
+ }
407
+ /**
408
+ * Insert one or more vectors.
409
+ *
410
+ * Wire: `POST /v1/vectors/collections/{name}/vectors` with
411
+ * `{ vectors: [{ id, values, metadata }] }`.
412
+ *
413
+ * Accepts either a single record or an array — the SDK always sends
414
+ * the wrapped `{ vectors: [...] }` envelope the gateway expects.
415
+ */
416
+ async insert(records) {
417
+ const vectors = Array.isArray(records) ? records : [records];
418
+ const { data } = await this.client._getHttpClient().post(
419
+ `${this.basePath}/vectors`,
420
+ { vectors }
421
+ );
422
+ return data?.data ?? data;
423
+ }
424
+ /**
425
+ * k-NN search over the vector collection.
426
+ *
427
+ * Wire: `POST /v1/vectors/collections/{name}/search` with
428
+ * `{ vector, k, include_metadata, filter? }`.
429
+ *
430
+ * Returns the bare array of hits — gateway envelope (`{data: [...]}`) is
431
+ * unwrapped automatically for parity with `Collection.vectorSearch`.
432
+ */
433
+ async search(options) {
434
+ const k = options.k ?? options.topK ?? 10;
435
+ const body = {
436
+ vector: options.vector,
437
+ k,
438
+ include_metadata: options.includeMetadata !== false
439
+ };
440
+ if (options.filter !== void 0) body.filter = options.filter;
441
+ const { data } = await this.client._getHttpClient().post(
442
+ `${this.basePath}/search`,
443
+ body
444
+ );
445
+ const inner = data?.data ?? data;
446
+ if (Array.isArray(inner)) return inner;
447
+ return inner?.matches ?? inner?.results ?? inner?.hits ?? [];
448
+ }
449
+ /**
450
+ * Fetch a single vector by id.
451
+ *
452
+ * Wire: `GET /v1/vectors/collections/{name}/vectors/{id}`. Returns the
453
+ * gateway payload `{ id, values, metadata }` (envelope unwrapped) or
454
+ * `null` on 404.
455
+ */
456
+ async get(id) {
457
+ try {
458
+ const { data } = await this.client._getHttpClient().get(
459
+ `${this.basePath}/vectors/${encodeURIComponent(id)}`
460
+ );
461
+ return data?.data ?? data;
462
+ } catch (err) {
463
+ if (err?.code === "NOT_FOUND" || err?.status === 404) return null;
464
+ throw err;
465
+ }
466
+ }
467
+ /**
468
+ * Delete one or more vectors by id.
469
+ *
470
+ * Single-id wire: `DELETE /v1/vectors/collections/{name}/vectors/{id}`.
471
+ * Bulk wire: `DELETE /v1/vectors/collections/{name}/vectors` with
472
+ * `{ ids: [...] }` body.
473
+ */
474
+ async delete(ids) {
475
+ if (typeof ids === "string") {
476
+ const { data: data2 } = await this.client._getHttpClient().delete(
477
+ `${this.basePath}/vectors/${encodeURIComponent(ids)}`
478
+ );
479
+ return data2?.data ?? data2;
480
+ }
481
+ const { data } = await this.client._getHttpClient().request({
482
+ method: "DELETE",
483
+ url: `${this.basePath}/vectors`,
484
+ data: { ids }
485
+ });
486
+ return data?.data ?? data;
487
+ }
488
+ /**
489
+ * Vector count.
490
+ *
491
+ * Wire: `GET /v1/vectors/collections/{name}/count` if the gateway
492
+ * exposes it, otherwise falls back to `info().vector_count`.
493
+ */
494
+ async count() {
495
+ try {
496
+ const { data } = await this.client._getHttpClient().get(`${this.basePath}/count`);
497
+ const inner = data?.data ?? data;
498
+ const n = typeof inner === "number" ? inner : inner?.count ?? inner?.vector_count;
499
+ if (typeof n === "number") return n;
500
+ } catch {
501
+ }
502
+ const info = await this.info();
503
+ return typeof info?.vector_count === "number" ? info.vector_count : 0;
504
+ }
505
+ /**
506
+ * Collection metadata.
507
+ *
508
+ * Wire: `GET /v1/vectors/collections/{name}` returning
509
+ * `{ name, dimensions, vector_count, distance_metric, index_type }`.
510
+ */
511
+ async info() {
512
+ const { data } = await this.client._getHttpClient().get(this.basePath);
513
+ return data?.data ?? data;
514
+ }
515
+ };
516
+
397
517
  // src/automl.ts
398
518
  var AutoMLModel = class {
399
519
  constructor(client, info) {
@@ -467,27 +587,48 @@ var AutoMLClient = class {
467
587
  return new AutoMLModel(this, modelInfo);
468
588
  }
469
589
  async getModel(modelId) {
470
- const { data } = await this.synapCores._getHttpClient().get(
471
- `/automl/models/${modelId}`
472
- );
473
- const modelInfo = {
474
- id: data.id,
475
- name: data.name,
476
- task: data.task,
477
- status: data.status,
478
- accuracy: data.accuracy,
479
- createdAt: new Date(data.created_at ?? Date.now()),
480
- updatedAt: data.updated_at ? new Date(data.updated_at) : void 0,
481
- config: data.config ?? {}
482
- };
483
- return new AutoMLModel(this, modelInfo);
590
+ try {
591
+ const { data } = await this.synapCores._getHttpClient().get(
592
+ `/automl/models/${modelId}`
593
+ );
594
+ const m = data?.data ?? data;
595
+ const modelInfo = {
596
+ id: m.id ?? modelId,
597
+ name: m.name ?? modelId,
598
+ task: m.task,
599
+ status: m.status,
600
+ accuracy: m.accuracy,
601
+ createdAt: new Date(m.created_at ?? Date.now()),
602
+ updatedAt: m.updated_at ? new Date(m.updated_at) : void 0,
603
+ config: m.config ?? {}
604
+ };
605
+ return new AutoMLModel(this, modelInfo);
606
+ } catch (err) {
607
+ const status = err?.statusCode ?? err?.response?.status;
608
+ const code = err?.code;
609
+ if (status === 404 || code === "NOT_FOUND") {
610
+ const modelInfo = {
611
+ id: modelId,
612
+ name: modelId,
613
+ task: void 0,
614
+ status: "unknown",
615
+ accuracy: void 0,
616
+ createdAt: /* @__PURE__ */ new Date(),
617
+ updatedAt: void 0,
618
+ config: {}
619
+ };
620
+ return new AutoMLModel(this, modelInfo);
621
+ }
622
+ throw err;
623
+ }
484
624
  }
485
625
  async listModels(filters) {
486
626
  const { data } = await this.synapCores._getHttpClient().get("/automl/models", {
487
627
  params: filters
488
628
  });
489
- return (data.models ?? data ?? []).map((model) => ({
490
- id: model.id,
629
+ 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 : [];
630
+ return list.map((model) => ({
631
+ id: model.id ?? model.name,
491
632
  name: model.name,
492
633
  task: model.task,
493
634
  status: model.status,
@@ -1998,23 +2139,24 @@ var GraphsApi = class {
1998
2139
  constructor(synapCores) {
1999
2140
  this.synapCores = synapCores;
2000
2141
  }
2142
+ // v0.3.0: gateway routes live under /graph/graphs, not /graphs.
2001
2143
  async list() {
2002
- const { data } = await this.synapCores._getHttpClient().get("/graphs");
2144
+ const { data } = await this.synapCores._getHttpClient().get("/graph/graphs");
2003
2145
  return (data.graphs ?? data ?? []).map((g) => this.normalize(g));
2004
2146
  }
2005
2147
  async create(name, opts = {}) {
2006
- const { data } = await this.synapCores._getHttpClient().post("/graphs", {
2148
+ const { data } = await this.synapCores._getHttpClient().post("/graph/graphs", {
2007
2149
  name,
2008
2150
  description: opts.description
2009
2151
  });
2010
2152
  return this.normalize(data);
2011
2153
  }
2012
2154
  async get(name) {
2013
- const { data } = await this.synapCores._getHttpClient().get(`/graphs/${name}`);
2155
+ const { data } = await this.synapCores._getHttpClient().get(`/graph/graphs/${name}`);
2014
2156
  return this.normalize(data);
2015
2157
  }
2016
2158
  async delete(name) {
2017
- await this.synapCores._getHttpClient().delete(`/graphs/${name}`);
2159
+ await this.synapCores._getHttpClient().delete(`/graph/graphs/${name}`);
2018
2160
  }
2019
2161
  normalize(data) {
2020
2162
  return {
@@ -2813,6 +2955,20 @@ var SynapCores = class {
2813
2955
  this.collectionsCache = /* @__PURE__ */ new Map();
2814
2956
  this.currentTransaction = null;
2815
2957
  this.preparedStatements = /* @__PURE__ */ new Map();
2958
+ // =================================================================
2959
+ // VECTOR COLLECTIONS — /v1/vectors/collections/{name}
2960
+ //
2961
+ // The gateway exposes two parallel "collection" worlds:
2962
+ // (a) document-store collections under /v1/collections (above), and
2963
+ // (b) vector collections under /v1/vectors/collections (below).
2964
+ //
2965
+ // v0.3.0 only wrapped (a) so vector-first users had to drop down to
2966
+ // `_getHttpClient()` to call (b) directly. v0.4.0 adds first-class
2967
+ // helpers — `createVectorCollection`, `vectorCollection(name)`,
2968
+ // `listVectorCollections`, `deleteVectorCollection` — that target (b)
2969
+ // and return a typed `VectorCollection` handle.
2970
+ // =================================================================
2971
+ this.vectorCollectionsCache = /* @__PURE__ */ new Map();
2816
2972
  this.config = {
2817
2973
  host: config.host || "localhost",
2818
2974
  port: config.port || 8080,
@@ -2835,14 +2991,14 @@ var SynapCores = class {
2835
2991
  if (this.config.jwtToken) {
2836
2992
  authHeader["Authorization"] = `Bearer ${this.config.jwtToken}`;
2837
2993
  } else if (this.config.apiKey) {
2838
- authHeader["X-API-Key"] = this.config.apiKey;
2994
+ authHeader["Authorization"] = `Bearer ${this.config.apiKey}`;
2839
2995
  }
2840
2996
  this.httpClient = import_axios.default.create({
2841
2997
  baseURL,
2842
2998
  timeout: this.config.timeout,
2843
2999
  headers: {
2844
3000
  "Content-Type": "application/json",
2845
- "User-Agent": "synapcores-nodejs/0.2.0",
3001
+ "User-Agent": "synapcores-nodejs/0.4.0",
2846
3002
  ...authHeader
2847
3003
  },
2848
3004
  ...httpsAgent && { httpsAgent }
@@ -3008,15 +3164,35 @@ var SynapCores = class {
3008
3164
  this.collectionsCache.set(name, collection);
3009
3165
  return collection;
3010
3166
  }
3167
+ /**
3168
+ * Synchronous accessor that returns a Collection handle without round-tripping
3169
+ * to the gateway. Use this when you already know the collection exists and just
3170
+ * want to issue a vectorSearch / search / insert against it.
3171
+ *
3172
+ * v0.3.0: added so `client.collection(name).vectorSearch(...)` works without
3173
+ * a preceding await on getCollection().
3174
+ */
3175
+ collection(name) {
3176
+ if (this.collectionsCache.has(name)) {
3177
+ return this.collectionsCache.get(name);
3178
+ }
3179
+ const c = new Collection(this, name);
3180
+ this.collectionsCache.set(name, c);
3181
+ return c;
3182
+ }
3011
3183
  /**
3012
3184
  * List collections (legacy method for backward compatibility)
3013
3185
  */
3014
3186
  async listCollections() {
3015
3187
  const result = await this.listCollectionsDetailed();
3016
- return result.collections.map((c) => c.name);
3188
+ return (result.collections ?? []).map((c) => c.name);
3017
3189
  }
3018
3190
  /**
3019
3191
  * List collections with detailed information matching the database integration guide format
3192
+ *
3193
+ * v0.3.0: gateway returns an envelope { data: { items, total, page, page_size, ... }, meta }.
3194
+ * We normalise that into the SDK's { collections, total, page, pageSize } shape and also
3195
+ * accept legacy { collections: [...] } / bare arrays for forward-compat.
3020
3196
  */
3021
3197
  async listCollectionsDetailed(options) {
3022
3198
  const params = new URLSearchParams();
@@ -3028,7 +3204,14 @@ var SynapCores = class {
3028
3204
  const { data } = await this.httpClient.get(
3029
3205
  `/collections${params.toString() ? `?${params.toString()}` : ""}`
3030
3206
  );
3031
- return data;
3207
+ const inner = data?.data ?? data;
3208
+ const items = Array.isArray(inner) ? inner : inner?.items ?? inner?.collections ?? [];
3209
+ return {
3210
+ collections: items,
3211
+ total: inner?.total ?? items.length,
3212
+ page: inner?.page ?? 1,
3213
+ pageSize: inner?.page_size ?? inner?.pageSize ?? items.length
3214
+ };
3032
3215
  }
3033
3216
  async getDocuments(collectionName, page, pageSize) {
3034
3217
  const { data } = await this.httpClient.get(
@@ -3040,6 +3223,67 @@ var SynapCores = class {
3040
3223
  await this.httpClient.delete(`/collections/${name}`);
3041
3224
  this.collectionsCache.delete(name);
3042
3225
  }
3226
+ /**
3227
+ * Create a vector collection.
3228
+ *
3229
+ * Wire: `POST /v1/vectors/collections` with
3230
+ * `{ name, dimensions, distance_metric }`. Distinct from
3231
+ * `createCollection`, which targets the document-store subsystem.
3232
+ *
3233
+ * @example
3234
+ * const coll = await client.createVectorCollection({
3235
+ * name: 'memory_v1', dimensions: 1536, distance_metric: 'cosine',
3236
+ * });
3237
+ * await coll.insert({ id: 'v1', values: [...], metadata: { ... } });
3238
+ */
3239
+ async createVectorCollection(options) {
3240
+ await this.httpClient.post("/vectors/collections", {
3241
+ name: options.name,
3242
+ dimensions: options.dimensions,
3243
+ distance_metric: options.distance_metric ?? "cosine"
3244
+ });
3245
+ const coll = new VectorCollection(this, options.name);
3246
+ this.vectorCollectionsCache.set(options.name, coll);
3247
+ return coll;
3248
+ }
3249
+ /**
3250
+ * Synchronous accessor for an existing vector collection. Does not
3251
+ * round-trip to the gateway — use `createVectorCollection` if you
3252
+ * need to provision the collection first, or `listVectorCollections`
3253
+ * to confirm existence.
3254
+ *
3255
+ * v0.4.0 split: this targets the **vector subsystem**
3256
+ * (`/v1/vectors/collections/{name}`). `client.collection(name)` still
3257
+ * returns a document-store `Collection` for the legacy subsystem.
3258
+ */
3259
+ vectorCollection(name) {
3260
+ const cached = this.vectorCollectionsCache.get(name);
3261
+ if (cached) return cached;
3262
+ const coll = new VectorCollection(this, name);
3263
+ this.vectorCollectionsCache.set(name, coll);
3264
+ return coll;
3265
+ }
3266
+ /**
3267
+ * List vector collections.
3268
+ *
3269
+ * Wire: `GET /v1/vectors/collections`. Returns the bare array of
3270
+ * collection-info objects (envelope unwrapped).
3271
+ */
3272
+ async listVectorCollections() {
3273
+ const { data } = await this.httpClient.get("/vectors/collections");
3274
+ const inner = data?.data ?? data;
3275
+ if (Array.isArray(inner)) return inner;
3276
+ return inner?.items ?? inner?.collections ?? [];
3277
+ }
3278
+ /**
3279
+ * Delete a vector collection.
3280
+ *
3281
+ * Wire: `DELETE /v1/vectors/collections/{name}`.
3282
+ */
3283
+ async deleteVectorCollection(name) {
3284
+ await this.httpClient.delete(`/vectors/collections/${encodeURIComponent(name)}`);
3285
+ this.vectorCollectionsCache.delete(name);
3286
+ }
3043
3287
  /**
3044
3288
  * Execute SQL query (legacy method for backward compatibility)
3045
3289
  * @deprecated Use executeQuery for new code
@@ -3954,7 +4198,7 @@ var SynapCores = class {
3954
4198
 
3955
4199
  // src/index.ts
3956
4200
  var import_zod = require("zod");
3957
- var VERSION = "0.2.0";
4201
+ var VERSION = "0.4.0";
3958
4202
  // Annotate the CommonJS export names for ESM import in node:
3959
4203
  0 && (module.exports = {
3960
4204
  AuthenticationError,
@@ -3989,6 +4233,7 @@ var VERSION = "0.2.0";
3989
4233
  Tx,
3990
4234
  VERSION,
3991
4235
  ValidationError,
4236
+ VectorCollection,
3992
4237
  VectorError,
3993
4238
  z
3994
4239
  });