memorysync-sdk 1.1.1 → 1.3.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
@@ -40,6 +40,445 @@ var ServerError = class extends MemorySyncError {
40
40
  }
41
41
  };
42
42
 
43
+ // src/connections.ts
44
+ var V2 = "/api/v2/integrations";
45
+ var V1 = "/api/v1/integrations";
46
+ function seg(value) {
47
+ return encodeURIComponent(String(value));
48
+ }
49
+ var Namespace = class {
50
+ constructor(request) {
51
+ this.req = request;
52
+ }
53
+ };
54
+ var SlackNamespace = class extends Namespace {
55
+ /**
56
+ * Channels the app can see and could be added.
57
+ *
58
+ * Private channels appear only where the deployment allows them *and* a human
59
+ * has invited the app, so this never widens what someone already granted.
60
+ */
61
+ availableChannels(connectionId, query) {
62
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/slack/available-channels`, { query });
63
+ }
64
+ /** Channels currently selected for syncing. */
65
+ channels(connectionId) {
66
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/slack/channels`);
67
+ }
68
+ /** Select channels for syncing. */
69
+ addChannels(connectionId, channelIds) {
70
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/slack/channels`, {
71
+ body: { channel_ids: channelIds }
72
+ });
73
+ }
74
+ /** Stop syncing one channel. */
75
+ removeChannel(connectionId, channelId) {
76
+ return this.req(
77
+ "DELETE",
78
+ `${V2}/connections/${seg(connectionId)}/slack/channels/${seg(channelId)}`
79
+ );
80
+ }
81
+ /**
82
+ * Channels this connection will never sync.
83
+ *
84
+ * The deployment-wide floor cannot be removed here; a tenant may only add to it.
85
+ */
86
+ exclusionPolicy(connectionId) {
87
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/slack/exclusion-policy`);
88
+ }
89
+ /** Replace this connection's additions to the exclusion policy. */
90
+ setExclusionPolicy(connectionId, policy) {
91
+ return this.req("PUT", `${V2}/connections/${seg(connectionId)}/slack/exclusion-policy`, {
92
+ body: policy
93
+ });
94
+ }
95
+ /** Slack users seen on this connection and who they map to. */
96
+ identities(connectionId) {
97
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/slack/identities`);
98
+ }
99
+ /** Map a Slack user to a MemorySync end user. */
100
+ linkIdentity(connectionId, body) {
101
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/slack/identities/link`, { body });
102
+ }
103
+ /** Re-read the Slack member list and refresh the identity table. */
104
+ syncIdentities(connectionId) {
105
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/slack/identities/sync`);
106
+ }
107
+ };
108
+ var GoogleDriveNamespace = class extends Namespace {
109
+ /** Config for rendering Google's own file picker in your UI. */
110
+ pickerConfig(connectionId) {
111
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/gdrive/picker-config`);
112
+ }
113
+ /** Files and folders selected for syncing. */
114
+ resources(connectionId, query) {
115
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/gdrive/resources`, { query });
116
+ }
117
+ /** Select files or folders for syncing. */
118
+ addResources(connectionId, body) {
119
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/gdrive/resources`, { body });
120
+ }
121
+ /** Stop syncing one file or folder. */
122
+ removeResource(connectionId, resourceId) {
123
+ return this.req(
124
+ "DELETE",
125
+ `${V2}/connections/${seg(connectionId)}/gdrive/resources/${seg(resourceId)}`
126
+ );
127
+ }
128
+ };
129
+ var S3Namespace = class extends Namespace {
130
+ /** Prefixes visible in the bucket that could be added. */
131
+ availablePrefixes(connectionId, query) {
132
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/s3/available-prefixes`, { query });
133
+ }
134
+ /** Prefixes currently selected for syncing. */
135
+ prefixes(connectionId) {
136
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/s3/prefixes`);
137
+ }
138
+ /** Select prefixes for syncing. */
139
+ addPrefixes(connectionId, prefixes) {
140
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/s3/prefixes`, {
141
+ body: { prefixes }
142
+ });
143
+ }
144
+ /**
145
+ * Stop syncing the given prefixes.
146
+ *
147
+ * The prefixes travel in the body rather than the path because they contain
148
+ * slashes, which is why this DELETE carries one.
149
+ */
150
+ removePrefixes(connectionId, prefixes) {
151
+ return this.req("DELETE", `${V2}/connections/${seg(connectionId)}/s3/prefixes`, {
152
+ body: { prefixes }
153
+ });
154
+ }
155
+ /** Keys and patterns this connection will never sync. */
156
+ exclusionPolicy(connectionId) {
157
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/s3/exclusion-policy`);
158
+ }
159
+ /** Replace this connection's additions to the exclusion policy. */
160
+ setExclusionPolicy(connectionId, policy) {
161
+ return this.req("PUT", `${V2}/connections/${seg(connectionId)}/s3/exclusion-policy`, {
162
+ body: policy
163
+ });
164
+ }
165
+ /** Effective S3 settings, including the per-object size ceiling. */
166
+ settings(connectionId) {
167
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/s3/settings`);
168
+ }
169
+ };
170
+ var GranolaNamespace = class extends Namespace {
171
+ /** Folders that could be added. */
172
+ availableFolders(connectionId, query) {
173
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/granola/available-folders`, { query });
174
+ }
175
+ /** Folders currently selected for syncing. */
176
+ folders(connectionId) {
177
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/granola/folders`);
178
+ }
179
+ /** Select folders for syncing. */
180
+ addFolders(connectionId, body) {
181
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/granola/folders`, { body });
182
+ }
183
+ /** Stop syncing one folder. */
184
+ removeFolder(connectionId, folderId) {
185
+ return this.req(
186
+ "DELETE",
187
+ `${V2}/connections/${seg(connectionId)}/granola/folders/${seg(folderId)}`
188
+ );
189
+ }
190
+ /** Folders and meetings this connection will never sync. */
191
+ exclusionPolicy(connectionId) {
192
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/granola/exclusion-policy`);
193
+ }
194
+ /** Replace this connection's additions to the exclusion policy. */
195
+ setExclusionPolicy(connectionId, policy) {
196
+ return this.req("PUT", `${V2}/connections/${seg(connectionId)}/granola/exclusion-policy`, {
197
+ body: policy
198
+ });
199
+ }
200
+ /** Meeting participants seen on this connection and who they map to. */
201
+ identities(connectionId) {
202
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/granola/identities`);
203
+ }
204
+ /** Map a participant to a MemorySync end user. */
205
+ linkIdentity(connectionId, body) {
206
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/granola/identities/link`, { body });
207
+ }
208
+ /** Move an existing mapping to a different end user. */
209
+ relinkIdentity(connectionId, body) {
210
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/granola/identities/relink`, { body });
211
+ }
212
+ /** Effective Granola settings for this connection. */
213
+ settings(connectionId) {
214
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/granola/settings`);
215
+ }
216
+ /** Update Granola settings for this connection. */
217
+ setSettings(connectionId, settings) {
218
+ return this.req("PUT", `${V2}/connections/${seg(connectionId)}/granola/settings`, {
219
+ body: settings
220
+ });
221
+ }
222
+ };
223
+ var ConnectionOAuthNamespace = class extends Namespace {
224
+ /**
225
+ * Begin an OAuth connection and get the URL to send the user to.
226
+ *
227
+ * The user completes consent in a browser and the provider calls the platform
228
+ * back — not your backend. Poll {@link status} to find out how it went.
229
+ */
230
+ initiate(provider, body = {}) {
231
+ return this.req("POST", `${V2}/oauth/initiate`, { body: { provider, ...body } });
232
+ }
233
+ /** Where an in-flight OAuth connection got to. */
234
+ status(query) {
235
+ return this.req("GET", `${V2}/oauth/status`, { query });
236
+ }
237
+ };
238
+ var ConnectionsNamespace = class extends Namespace {
239
+ constructor(request) {
240
+ super(request);
241
+ this.slack = new SlackNamespace(request);
242
+ this.gdrive = new GoogleDriveNamespace(request);
243
+ this.s3 = new S3Namespace(request);
244
+ this.granola = new GranolaNamespace(request);
245
+ this.oauth = new ConnectionOAuthNamespace(request);
246
+ }
247
+ /** Every connection in this organization. */
248
+ list(query) {
249
+ return this.req("GET", `${V2}/connections`, { query });
250
+ }
251
+ /** One connection, including its status and last sync. */
252
+ get(connectionId) {
253
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}`);
254
+ }
255
+ /** Connect a provider that authenticates with an API key or bot token. */
256
+ createWithApiKey(provider, apiKey, body = {}) {
257
+ return this.req("POST", `${V2}/connections/api-key`, {
258
+ body: { provider, api_key: apiKey, ...body }
259
+ });
260
+ }
261
+ /** Connect a provider that needs a credential bundle, such as S3 keys. */
262
+ createWithCredentials(provider, credentials, body = {}) {
263
+ return this.req("POST", `${V2}/connections/credentials`, {
264
+ body: { provider, credentials, ...body }
265
+ });
266
+ }
267
+ /** Change a connection's name, schedule or settings. */
268
+ update(connectionId, body) {
269
+ return this.req("PATCH", `${V2}/connections/${seg(connectionId)}`, { body });
270
+ }
271
+ /**
272
+ * Remove a connection.
273
+ *
274
+ * Stops future syncing. Memories already extracted are left in place — use
275
+ * {@link purge} for those, so disconnecting never silently deletes knowledge
276
+ * someone still depends on.
277
+ */
278
+ delete(connectionId) {
279
+ return this.req("DELETE", `${V2}/connections/${seg(connectionId)}`);
280
+ }
281
+ /** Re-authorise a connection whose credentials expired or were revoked. */
282
+ reconnect(connectionId, body = {}) {
283
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/reconnect`, { body });
284
+ }
285
+ /**
286
+ * Delete the memories this connection produced.
287
+ *
288
+ * Separate from {@link delete} on purpose: removing a connection and removing
289
+ * what it taught you are different decisions.
290
+ */
291
+ purge(connectionId, body = {}) {
292
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/purge`, { body });
293
+ }
294
+ /** Current and recent sync state for a connection. */
295
+ syncStatus(connectionId) {
296
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/sync`);
297
+ }
298
+ /** Start a sync now instead of waiting for the schedule. */
299
+ triggerSync(connectionId, body = {}) {
300
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/sync`, { body });
301
+ }
302
+ /** Objects a connection has ingested — files, messages, meetings. */
303
+ objects(connectionId, query) {
304
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/objects`, { query });
305
+ }
306
+ /** Object listing with richer filtering and paging than {@link objects}. */
307
+ objectsV2(connectionId, query) {
308
+ return this.req("GET", `${V2}/connections/${seg(connectionId)}/objects/v2`, { query });
309
+ }
310
+ /** Apply one action to many objects — pause, resume, re-extract. */
311
+ bulkObjectAction(connectionId, body) {
312
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/objects/bulk`, { body });
313
+ }
314
+ /** Connector totals: connections, objects synced, memories produced. */
315
+ stats(query) {
316
+ return this.req("GET", `${V2}/stats`, { query });
317
+ }
318
+ /** Audit trail of connector activity. */
319
+ auditLogs(query) {
320
+ return this.req("GET", `${V2}/audit-logs`, { query });
321
+ }
322
+ };
323
+ var ObjectsNamespace = class extends Namespace {
324
+ /** Metadata and sync state for one object. */
325
+ get(objectId) {
326
+ return this.req("GET", `${V2}/objects/${seg(objectId)}`);
327
+ }
328
+ /** What extraction made of this object. */
329
+ analysis(objectId) {
330
+ return this.req("GET", `${V2}/objects/${seg(objectId)}/analysis`);
331
+ }
332
+ /** Every action taken on this object. */
333
+ audit(objectId, query) {
334
+ return this.req("GET", `${V2}/objects/${seg(objectId)}/audit`, { query });
335
+ }
336
+ /** Versions of this object seen across syncs. */
337
+ history(objectId, query) {
338
+ return this.req("GET", `${V2}/objects/${seg(objectId)}/history`, { query });
339
+ }
340
+ /** Which memories this object produced, and whether extraction finished. */
341
+ memoryStatus(objectId) {
342
+ return this.req("GET", `${V2}/objects/${seg(objectId)}/memory-status`);
343
+ }
344
+ /** Row and column statistics for spreadsheet-shaped objects. */
345
+ structuredStats(objectId) {
346
+ return this.req("GET", `${V2}/objects/${seg(objectId)}/structured-stats`);
347
+ }
348
+ /** Score this object for extraction worthiness without extracting. */
349
+ evaluate(objectId, body = {}) {
350
+ return this.req("POST", `${V2}/objects/${seg(objectId)}/evaluate`, { body });
351
+ }
352
+ /** Stop re-syncing this object, leaving its memories in place. */
353
+ pause(objectId) {
354
+ return this.req("POST", `${V2}/objects/${seg(objectId)}/pause`);
355
+ }
356
+ /** Resume syncing a paused object. */
357
+ resume(objectId) {
358
+ return this.req("POST", `${V2}/objects/${seg(objectId)}/resume`);
359
+ }
360
+ /**
361
+ * Run extraction again over content already fetched.
362
+ *
363
+ * Counts against the plan's add allowance, exactly like the first extraction,
364
+ * because it creates memories the same way.
365
+ */
366
+ reextract(objectId, body = {}) {
367
+ return this.req("POST", `${V2}/objects/${seg(objectId)}/reextract`, { body });
368
+ }
369
+ /** Fetch this object from the provider again, then extract. */
370
+ resync(objectId, body = {}) {
371
+ return this.req("POST", `${V2}/objects/${seg(objectId)}/resync`, { body });
372
+ }
373
+ /** Remove the memories this object produced, keeping the object record. */
374
+ deleteMemories(objectId, query) {
375
+ return this.req("DELETE", `${V2}/objects/${seg(objectId)}/memories`, { query });
376
+ }
377
+ };
378
+ var ProvidersNamespace = class extends Namespace {
379
+ /** Every available provider and what it needs to connect. */
380
+ list(query) {
381
+ return this.req("GET", `${V2}/providers`, { query });
382
+ }
383
+ /** One provider's capabilities, scopes and settings schema. */
384
+ get(providerId) {
385
+ return this.req("GET", `${V2}/providers/${seg(providerId)}`);
386
+ }
387
+ };
388
+ var SyncJobsNamespace = class extends Namespace {
389
+ /** Progress and outcome of one sync run. */
390
+ get(jobId) {
391
+ return this.req("GET", `${V2}/sync-jobs/${seg(jobId)}`);
392
+ }
393
+ /** Stop a running sync. Objects already ingested are kept. */
394
+ cancel(jobId, body = {}) {
395
+ return this.req("POST", `${V2}/sync-jobs/${seg(jobId)}/cancel`, { body });
396
+ }
397
+ };
398
+ var WebCrawlerNamespace = class extends Namespace {
399
+ /** Check a URL is reachable and crawlable before committing to a job. */
400
+ validate(url, body = {}) {
401
+ return this.req("POST", `${V1}/web-crawler/validate`, { body: { url, ...body } });
402
+ }
403
+ /**
404
+ * Start a crawl. Returns a job to poll.
405
+ *
406
+ * Crawling only fetches and stores page content. Nothing becomes a memory until
407
+ * you call {@link importJob}, so a large crawl cannot quietly consume your add
408
+ * allowance.
409
+ */
410
+ crawl(url, body = {}) {
411
+ return this.req("POST", `${V1}/web-crawler/crawl`, { body: { url, ...body } });
412
+ }
413
+ /** Crawl jobs for this organization. */
414
+ jobs(query) {
415
+ return this.req("GET", `${V1}/web-crawler/jobs`, { query });
416
+ }
417
+ /** One crawl job's status and progress. */
418
+ job(jobId) {
419
+ return this.req("GET", `${V1}/web-crawler/jobs/${seg(jobId)}`);
420
+ }
421
+ /** Stop a running crawl. Pages already fetched are kept. */
422
+ cancelJob(jobId) {
423
+ return this.req("POST", `${V1}/web-crawler/jobs/${seg(jobId)}/cancel`);
424
+ }
425
+ /** Delete a crawl job and its fetched pages. */
426
+ deleteJob(jobId) {
427
+ return this.req("DELETE", `${V1}/web-crawler/jobs/${seg(jobId)}`);
428
+ }
429
+ /** Pages a crawl fetched, before any import. */
430
+ jobContent(jobId, query) {
431
+ return this.req("GET", `${V1}/web-crawler/jobs/${seg(jobId)}/content`, { query });
432
+ }
433
+ /** Page counts, byte totals and error breakdown for a crawl. */
434
+ jobStatistics(jobId) {
435
+ return this.req("GET", `${V1}/web-crawler/jobs/${seg(jobId)}/statistics`);
436
+ }
437
+ /**
438
+ * Turn a completed crawl's pages into memories.
439
+ *
440
+ * This is the step that creates memories, so this is the step that is billed —
441
+ * one unit per memory created, like every other ingestion path.
442
+ */
443
+ importJob(jobId, body = {}) {
444
+ return this.req("POST", `${V1}/web-crawler/jobs/${seg(jobId)}/import`, { body });
445
+ }
446
+ /** Crawls running right now. */
447
+ active() {
448
+ return this.req("GET", `${V1}/web-crawler/active`);
449
+ }
450
+ /** Crawler limits in force: depth, page ceiling, rate, timeouts. */
451
+ config() {
452
+ return this.req("GET", `${V1}/web-crawler/config`);
453
+ }
454
+ };
455
+ var IntegrationsNamespace = class extends Namespace {
456
+ constructor(request) {
457
+ super(request);
458
+ this.webCrawler = new WebCrawlerNamespace(request);
459
+ }
460
+ /** Every integration this deployment offers, for building a picker UI. */
461
+ catalog(query) {
462
+ return this.req("GET", `${V1}/catalog`, { query });
463
+ }
464
+ /** Integrations currently connected. Older view of `connections.list()`. */
465
+ connected(query) {
466
+ return this.req("GET", `${V1}/connected`, { query });
467
+ }
468
+ /** Legacy integration counters. Prefer `connections.stats()`. */
469
+ stats(query) {
470
+ return this.req("GET", `${V1}/stats`, { query });
471
+ }
472
+ /** Update a legacy integration record. */
473
+ update(integrationId, body) {
474
+ return this.req("PATCH", `${V1}/${seg(integrationId)}`, { body });
475
+ }
476
+ /** Delete a legacy integration record. */
477
+ delete(integrationId) {
478
+ return this.req("DELETE", `${V1}/${seg(integrationId)}`);
479
+ }
480
+ };
481
+
43
482
  // src/control-plane.ts
44
483
  var SDK_VERSION = "1.1.1";
45
484
  function safeJson(text) {
@@ -467,7 +906,7 @@ var ControlPlaneClient = class {
467
906
  };
468
907
 
469
908
  // src/index.ts
470
- var SDK_VERSION2 = "1.1.0";
909
+ var SDK_VERSION2 = "1.3.0";
471
910
  function camelToSnakeKey(key) {
472
911
  return key.replace(/([A-Z])/g, "_$1").toLowerCase();
473
912
  }
@@ -496,6 +935,22 @@ function snakeToCamelMemory(m) {
496
935
  score: m.score ?? null
497
936
  };
498
937
  }
938
+ function buildQuery(params) {
939
+ if (!params) return "";
940
+ const search = new URLSearchParams();
941
+ for (const [key, value] of Object.entries(params)) {
942
+ if (value === void 0 || value === null) continue;
943
+ if (Array.isArray(value)) {
944
+ for (const item of value) {
945
+ if (item !== void 0 && item !== null) search.append(key, String(item));
946
+ }
947
+ } else {
948
+ search.append(key, String(value));
949
+ }
950
+ }
951
+ const qs = search.toString();
952
+ return qs ? `?${qs}` : "";
953
+ }
499
954
  function safeJson2(text) {
500
955
  try {
501
956
  return JSON.parse(text);
@@ -541,6 +996,12 @@ var MemorySyncClient = class {
541
996
  throw new Error("No fetch implementation available. Pass `fetch` in config or use Node 18+.");
542
997
  }
543
998
  this.fetchImpl = f;
999
+ const request = (method, path, options) => this.request(method, path, options ?? {});
1000
+ this.connections = new ConnectionsNamespace(request);
1001
+ this.objects = new ObjectsNamespace(request);
1002
+ this.providers = new ProvidersNamespace(request);
1003
+ this.syncJobs = new SyncJobsNamespace(request);
1004
+ this.integrations = new IntegrationsNamespace(request);
544
1005
  }
545
1006
  headers(extra = {}) {
546
1007
  const h = {
@@ -555,17 +1016,20 @@ var MemorySyncClient = class {
555
1016
  return h;
556
1017
  }
557
1018
  async request(method, path, options = {}) {
558
- const url = `${this.baseUrl}${path}`;
1019
+ const url = `${this.baseUrl}${path}${buildQuery(options.query)}`;
559
1020
  const controller = new AbortController();
560
1021
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
561
1022
  try {
562
1023
  const headers = this.headers(
563
1024
  options.endUserOverride ? { "X-End-User-ID": options.endUserOverride } : {}
564
1025
  );
1026
+ if (options.form) {
1027
+ delete headers["Content-Type"];
1028
+ }
565
1029
  const res = await this.fetchImpl(url, {
566
1030
  method,
567
1031
  headers,
568
- body: options.body !== void 0 ? JSON.stringify(options.body) : void 0,
1032
+ body: options.form ? options.form : options.body !== void 0 ? JSON.stringify(options.body) : void 0,
569
1033
  signal: controller.signal
570
1034
  });
571
1035
  const requestId = res.headers.get("X-Request-ID") ?? void 0;
@@ -692,14 +1156,51 @@ var MemorySyncClient = class {
692
1156
  const raw = await this.request("PATCH", `/memory/${memoryId}`, { body });
693
1157
  return snakeToCamelMemory(raw);
694
1158
  }
695
- async forget(memoryIds, reason) {
696
- if (!Array.isArray(memoryIds) || memoryIds.length === 0) {
697
- throw new ValidationError("memoryIds must be a non-empty array");
1159
+ async forget(arg, legacyReason) {
1160
+ const req = Array.isArray(arg) ? { memoryIds: arg, reason: legacyReason } : arg;
1161
+ const hasIds = req.memoryIds !== void 0;
1162
+ const hasFilters = req.filters !== void 0;
1163
+ if (hasIds && hasFilters) {
1164
+ throw new ValidationError("Provide either memoryIds or filters, not both");
1165
+ }
1166
+ if (!hasIds && !hasFilters) {
1167
+ throw new ValidationError("Provide either memoryIds or filters");
698
1168
  }
699
- const body = { memory_ids: memoryIds };
700
- if (reason !== void 0) body.reason = reason;
1169
+ const body = {};
1170
+ if (hasIds) {
1171
+ if (!Array.isArray(req.memoryIds) || req.memoryIds.length === 0) {
1172
+ throw new ValidationError("memoryIds must be a non-empty array");
1173
+ }
1174
+ body.memory_ids = req.memoryIds;
1175
+ } else {
1176
+ const f = req.filters;
1177
+ const filters = {};
1178
+ if (f.source !== void 0) filters.source = f.source;
1179
+ if (f.eventType !== void 0) filters.event_type = f.eventType;
1180
+ if (f.tags !== void 0) filters.tags = f.tags;
1181
+ if (f.tier !== void 0) filters.tier = f.tier;
1182
+ if (f.before !== void 0) filters.before = f.before;
1183
+ if (f.after !== void 0) filters.after = f.after;
1184
+ if (Object.keys(filters).length === 0) {
1185
+ throw new ValidationError(
1186
+ "filters must set at least one criterion; use purgeUser() to remove everything for an end user"
1187
+ );
1188
+ }
1189
+ body.filters = filters;
1190
+ if (req.dryRun) body.dry_run = true;
1191
+ }
1192
+ if (req.reason !== void 0) body.reason = req.reason;
701
1193
  return await this.request("DELETE", "/memory/forget", { body });
702
1194
  }
1195
+ /**
1196
+ * Delete every memory belonging to the calling end user.
1197
+ *
1198
+ * Separate from {@link forget} on purpose: this reads like what it does, so a
1199
+ * whole-namespace delete can never be the accidental result of an empty filter.
1200
+ */
1201
+ async purgeUser() {
1202
+ return await this.request("DELETE", "/memory/user/purge") ?? {};
1203
+ }
703
1204
  async summarize(req) {
704
1205
  if (!req.memoryIds || req.memoryIds.length === 0) {
705
1206
  throw new ValidationError("summarize() requires memoryIds");
@@ -757,15 +1258,370 @@ var MemorySyncClient = class {
757
1258
  createdAt: raw.created_at
758
1259
  };
759
1260
  }
1261
+ // ── Files ──────────────────────────────────────────────────────────
1262
+ /**
1263
+ * Ingest a document and store the memories extracted from its text.
1264
+ *
1265
+ * Accepts the formats the connectors accept — PDF, DOCX, PPTX, XLSX, CSV,
1266
+ * text, Markdown, HTML, source code, and images/audio/video where
1267
+ * transcription is configured.
1268
+ *
1269
+ * Billed as an add, one unit per memory created. Resolves to the first stored
1270
+ * memory, or an {@link AddSkippedResponse} when the file yielded nothing worth
1271
+ * keeping — a blank scan, a sheet of empty cells, or content the extractor
1272
+ * judges trivial are all normal outcomes rather than errors.
1273
+ */
1274
+ async upload(req) {
1275
+ if (!req.filename?.trim()) {
1276
+ throw new ValidationError("filename is required so the server can pick a parser");
1277
+ }
1278
+ const form = new FormData();
1279
+ const blob = req.file instanceof Uint8Array ? new Blob([req.file], {
1280
+ type: req.contentType ?? "application/octet-stream"
1281
+ }) : req.file;
1282
+ form.append("file", blob, req.filename);
1283
+ if (req.source !== void 0) form.append("source", req.source);
1284
+ if (req.metadata !== void 0) form.append("metadata", JSON.stringify(req.metadata));
1285
+ if (req.endUserId !== void 0) form.append("end_user_id", req.endUserId);
1286
+ const raw = await this.request("POST", "/memory/upload", {
1287
+ form,
1288
+ endUserOverride: req.endUserId
1289
+ });
1290
+ if (raw && raw.status === "skipped") {
1291
+ return {
1292
+ status: "skipped",
1293
+ reason: raw.reason ?? "no_extractable_text",
1294
+ memoryIds: raw.memory_ids ?? [],
1295
+ candidatesExtracted: raw.candidates_extracted ?? 0,
1296
+ candidatesStored: raw.candidates_stored ?? 0
1297
+ };
1298
+ }
1299
+ return snakeToCamelMemory(raw);
1300
+ }
1301
+ // ── Bulk edit ──────────────────────────────────────────────────────
1302
+ /**
1303
+ * Apply many metadata edits in one request.
1304
+ *
1305
+ * Editable: `tags`, `importance`, `metadata`, `source`, `eventType`. A memory's
1306
+ * text, embeddings, owner, environment and project are not editable.
1307
+ *
1308
+ * Applied in one transaction, so the batch either lands or it does not — but an
1309
+ * id the caller cannot see is reported per item rather than failing the request.
1310
+ */
1311
+ async batchUpdate(items) {
1312
+ if (!Array.isArray(items) || items.length === 0) {
1313
+ throw new ValidationError("items must contain at least one entry");
1314
+ }
1315
+ if (items.length > 100) {
1316
+ throw new ValidationError("items may contain at most 100 entries per request");
1317
+ }
1318
+ const seen = /* @__PURE__ */ new Map();
1319
+ const payload = items.map((item, index) => {
1320
+ if (!Number.isInteger(item.memoryId) || item.memoryId <= 0) {
1321
+ throw new ValidationError(`items[${index}].memoryId must be a positive integer`);
1322
+ }
1323
+ const o = { memory_id: item.memoryId };
1324
+ if (item.tags !== void 0) o.tags = item.tags;
1325
+ if (item.importance !== void 0) o.importance = item.importance;
1326
+ if (item.metadata !== void 0) o.metadata = item.metadata;
1327
+ if (item.source !== void 0) o.source = item.source;
1328
+ if (item.eventType !== void 0) o.event_type = item.eventType;
1329
+ if (Object.keys(o).length === 1) {
1330
+ throw new ValidationError(
1331
+ `items[${index}] (memoryId ${item.memoryId}): at least one updatable field must be provided`
1332
+ );
1333
+ }
1334
+ const previous = seen.get(item.memoryId);
1335
+ if (previous !== void 0) {
1336
+ throw new ValidationError(
1337
+ `items must not contain the same memoryId twice: ${item.memoryId} appears at index ${previous} and ${index}`
1338
+ );
1339
+ }
1340
+ seen.set(item.memoryId, index);
1341
+ return o;
1342
+ });
1343
+ const raw = await this.request("POST", "/memory/batch-update", {
1344
+ body: { items: payload }
1345
+ });
1346
+ return {
1347
+ total: raw?.total ?? 0,
1348
+ updated: raw?.updated ?? 0,
1349
+ notFound: raw?.not_found ?? 0,
1350
+ results: (raw?.results ?? []).map((r) => ({
1351
+ index: r.index,
1352
+ memoryId: r.memory_id,
1353
+ status: r.status,
1354
+ changedFields: r.changed_fields ?? []
1355
+ }))
1356
+ };
1357
+ }
1358
+ // ── History and feedback ───────────────────────────────────────────
1359
+ /**
1360
+ * Recorded changes to one memory, oldest first.
1361
+ *
1362
+ * Entry 0 is the creation. Later entries carry the old and new value per field.
1363
+ * Entries written by background workers have `actor: null`. Only
1364
+ * user-meaningful fields are tracked; the watched list comes back in
1365
+ * `trackedFields`.
1366
+ */
1367
+ async history(memoryId, opts = {}) {
1368
+ if (!Number.isInteger(memoryId) || memoryId <= 0) {
1369
+ throw new ValidationError("memoryId must be a positive integer");
1370
+ }
1371
+ const raw = await this.request(
1372
+ "GET",
1373
+ `/memory/${memoryId}/history`,
1374
+ { query: { limit: opts.limit ?? 100, offset: opts.offset ?? 0 } }
1375
+ );
1376
+ return {
1377
+ memoryId: raw?.memory_id ?? memoryId,
1378
+ total: raw?.total ?? 0,
1379
+ revisions: (raw?.revisions ?? []).map((r) => ({
1380
+ revision: r.revision,
1381
+ event: r.event,
1382
+ changedFields: r.changed_fields ?? [],
1383
+ diff: r.diff ?? {},
1384
+ actor: r.actor ?? null,
1385
+ createdAt: r.created_at
1386
+ })),
1387
+ trackedFields: raw?.tracked_fields ?? []
1388
+ };
1389
+ }
1390
+ /**
1391
+ * Tell MemorySync whether a memory was useful.
1392
+ *
1393
+ * By default this moves the memory's `importance`, a weighted retrieval-ranking
1394
+ * factor, so a memory marked useful surfaces more readily and one marked wrong
1395
+ * surfaces less. The size of the move is adaptive: consistent signals amplify
1396
+ * it, mixed signals damp it. Importance is clamped to [0.05, 1.0], so no run of
1397
+ * negative feedback can make a memory permanently unreachable. Not billed.
1398
+ */
1399
+ async feedback(memoryId, signal, opts = {}) {
1400
+ if (!Number.isInteger(memoryId) || memoryId <= 0) {
1401
+ throw new ValidationError("memoryId must be a positive integer");
1402
+ }
1403
+ const valid = ["positive", "negative", "retrieved", "ignored"];
1404
+ if (!valid.includes(signal)) {
1405
+ throw new ValidationError(`signal must be one of ${valid.join(", ")}; got ${String(signal)}`);
1406
+ }
1407
+ const body = { signal };
1408
+ if (opts.comment !== void 0) body.comment = opts.comment;
1409
+ const raw = await this.request(
1410
+ "POST",
1411
+ `/memory/${memoryId}/feedback`,
1412
+ { body }
1413
+ );
1414
+ const summary = raw?.summary ?? {};
1415
+ const trend = summary.trend ?? {};
1416
+ return {
1417
+ memoryId: raw?.memory_id ?? memoryId,
1418
+ signal: raw?.signal ?? signal,
1419
+ importanceBefore: raw?.importance_before ?? 0,
1420
+ importanceAfter: raw?.importance_after ?? 0,
1421
+ adjustment: raw?.adjustment ?? 0,
1422
+ influencedRanking: Boolean(raw?.influenced_ranking),
1423
+ summary: {
1424
+ totalSignals: summary.total_signals ?? 0,
1425
+ signalCounts: summary.signal_counts ?? {},
1426
+ trend: {
1427
+ momentum: trend.momentum ?? "neutral",
1428
+ consistency: trend.consistency ?? 0,
1429
+ trendMultiplier: trend.trend_multiplier ?? 1,
1430
+ recentCount: trend.recent_count ?? 0
1431
+ }
1432
+ }
1433
+ };
1434
+ }
1435
+ // ── Ontology ───────────────────────────────────────────────────────
1436
+ /** The memory vocabulary in effect for this organization. */
1437
+ async getOntology() {
1438
+ const raw = await this.request("GET", "/memory/ontology");
1439
+ return toOntology(raw);
1440
+ }
1441
+ /**
1442
+ * Replace this organization's *additions* to the vocabulary.
1443
+ *
1444
+ * The two vocabularies are independent: omit one and it is left untouched, so
1445
+ * adding a content type cannot wipe your relation types. Pass an empty array to
1446
+ * clear a vocabulary's custom entries. The built-in types always remain.
1447
+ */
1448
+ async updateOntology(req) {
1449
+ if (req.contentTypes === void 0 && req.relationTypes === void 0) {
1450
+ throw new ValidationError(
1451
+ "provide contentTypes, relationTypes, or both; an empty request would silently do nothing"
1452
+ );
1453
+ }
1454
+ const body = {};
1455
+ if (req.contentTypes !== void 0) body.content_types = req.contentTypes;
1456
+ if (req.relationTypes !== void 0) body.relation_types = req.relationTypes;
1457
+ const raw = await this.request("PUT", "/memory/ontology", { body });
1458
+ return toOntology(raw);
1459
+ }
1460
+ // ── Retrieval variants ─────────────────────────────────────────────
1461
+ /**
1462
+ * Alias of {@link query} against `/memory/retrieve`.
1463
+ *
1464
+ * Both paths are live, and integrators arriving from other platforms reach for
1465
+ * `retrieve`. Identical semantics.
1466
+ */
1467
+ async retrieve(req) {
1468
+ const body = { query: req.query };
1469
+ if (req.k !== void 0) body.k = req.k;
1470
+ if (req.filters !== void 0) body.filters = camelToSnakeShallow(req.filters);
1471
+ if (req.sessionId !== void 0) body.session_id = req.sessionId;
1472
+ if (req.traversalDepth !== void 0) body.traversal_depth = req.traversalDepth;
1473
+ const raw = await this.request("POST", "/memory/retrieve", { body });
1474
+ return {
1475
+ memories: (raw.memories ?? []).map(snakeToCamelMemory),
1476
+ context: raw.context ?? null,
1477
+ latencyMs: raw.latency_ms ?? null,
1478
+ sessionId: raw.session_id ?? null,
1479
+ queryIntent: raw.query_intent ?? null
1480
+ };
1481
+ }
1482
+ /**
1483
+ * Route a question to the best knowledge source and answer from it.
1484
+ *
1485
+ * Returns the raw payload: the response carries routing diagnostics whose shape
1486
+ * is richer and more volatile than an SDK should freeze into an interface.
1487
+ */
1488
+ async searchRouted(query, opts = {}) {
1489
+ const body = { query };
1490
+ if (opts.k !== void 0) body.k = opts.k;
1491
+ if (opts.route !== void 0) body.route = opts.route;
1492
+ if (opts.includeReasoning !== void 0) body.include_reasoning = opts.includeReasoning;
1493
+ return await this.request("POST", "/memory/search/routed", { body }) ?? {};
1494
+ }
1495
+ /** Compose an answer across several memories, with citations. */
1496
+ async synthesize(opts = {}) {
1497
+ const body = {};
1498
+ if (opts.query !== void 0) body.query = opts.query;
1499
+ if (opts.memoryIds !== void 0) body.memory_ids = opts.memoryIds;
1500
+ if (opts.maxMemories !== void 0) body.max_memories = opts.maxMemories;
1501
+ return await this.request("POST", "/memory/synthesize", { body }) ?? {};
1502
+ }
1503
+ /** Re-embed this end user's memories. Returns immediately (`202`). */
1504
+ async refresh() {
1505
+ return await this.request("POST", "/memory/refresh") ?? {};
1506
+ }
1507
+ // ── Intelligence and graph ─────────────────────────────────────────
1508
+ /** Nodes and typed edges for this end user's memory graph. */
1509
+ async graph(opts = {}) {
1510
+ return await this.request("GET", "/memory/graph", {
1511
+ query: { limit: opts.limit, memory_id: opts.memoryId, depth: opts.depth }
1512
+ }) ?? {};
1513
+ }
1514
+ /** Semantic clusters over this end user's memories. */
1515
+ async clusters(opts = {}) {
1516
+ return await this.request("GET", "/memory/clusters", {
1517
+ query: { limit: opts.limit }
1518
+ }) ?? {};
1519
+ }
1520
+ /** Contradictions and open decisions detected across memories. */
1521
+ async decisions(opts = {}) {
1522
+ return await this.request("GET", "/memory/decisions", {
1523
+ query: { limit: opts.limit }
1524
+ }) ?? {};
1525
+ }
1526
+ /** Record which side of a contradiction wins. */
1527
+ async resolveDecision(opts = {}) {
1528
+ const body = {};
1529
+ if (opts.decisionId !== void 0) body.decision_id = opts.decisionId;
1530
+ if (opts.winningMemoryId !== void 0) body.winning_memory_id = opts.winningMemoryId;
1531
+ if (opts.resolution !== void 0) body.resolution = opts.resolution;
1532
+ if (opts.note !== void 0) body.note = opts.note;
1533
+ return await this.request("POST", "/memory/decision/resolve", { body }) ?? {};
1534
+ }
1535
+ /**
1536
+ * The intelligence report: themes, entities, patterns, dual-horizon view.
1537
+ *
1538
+ * `scope` is explicit by design server-side — nothing is inferred, so if you do
1539
+ * not ask for a scope you do not get it.
1540
+ */
1541
+ async intelligence(opts = {}) {
1542
+ return await this.request("GET", "/memory/intelligence", {
1543
+ query: { limit: opts.limit, scope: opts.scope, project_id: opts.projectId }
1544
+ }) ?? {};
1545
+ }
1546
+ /** Counts and coverage for the knowledge base. */
1547
+ async knowledgeStats() {
1548
+ return await this.request("GET", "/memory/knowledge/stats") ?? {};
1549
+ }
1550
+ // ── v1 data plane ──────────────────────────────────────────────────
1551
+ /** Add a conversation turn and extract memories from it. */
1552
+ async addTurn(req) {
1553
+ const body = {
1554
+ tenant_id: req.tenantId,
1555
+ user_id: req.userId,
1556
+ messages: req.messages
1557
+ };
1558
+ if (req.sessionId !== void 0) body.session_id = req.sessionId;
1559
+ if (req.metadata !== void 0) body.metadata = req.metadata;
1560
+ return await this.request("POST", "/v1/memory/add_turn", { body }) ?? {};
1561
+ }
1562
+ /**
1563
+ * Build a prompt-ready context block for an LLM call.
1564
+ *
1565
+ * `types` narrows the result to those content types. Names outside the
1566
+ * organization's vocabulary are dropped rather than rejected, so a stale client
1567
+ * gets a narrower answer instead of an error.
1568
+ */
1569
+ async recall(req) {
1570
+ const body = {
1571
+ tenant_id: req.tenantId,
1572
+ user_id: req.userId,
1573
+ prompt: req.prompt
1574
+ };
1575
+ if (req.k !== void 0) body.k = req.k;
1576
+ if (req.types !== void 0) body.types = req.types;
1577
+ return await this.request("POST", "/v1/memory/recall", { body }) ?? {};
1578
+ }
1579
+ /** Async ingestion status for one memory. */
1580
+ async status(memoryId) {
1581
+ if (!Number.isInteger(memoryId) || memoryId <= 0) {
1582
+ throw new ValidationError("memoryId must be a positive integer");
1583
+ }
1584
+ return await this.request("GET", `/v1/memory/status/${memoryId}`) ?? {};
1585
+ }
1586
+ /** Page through a specific end user's memories. */
1587
+ async listMemories(req) {
1588
+ return await this.request(
1589
+ "GET",
1590
+ `/v1/memory/${encodeURIComponent(req.tenantId)}/${encodeURIComponent(req.userId)}/list`,
1591
+ { query: { limit: req.limit, offset: req.offset } }
1592
+ ) ?? {};
1593
+ }
760
1594
  };
1595
+ function toOntology(raw) {
1596
+ return {
1597
+ contentTypes: raw?.content_types ?? [],
1598
+ relationTypes: raw?.relation_types ?? [],
1599
+ builtinContentTypes: raw?.builtin_content_types ?? [],
1600
+ builtinRelationTypes: raw?.builtin_relation_types ?? [],
1601
+ customContentTypes: raw?.custom_content_types ?? [],
1602
+ customRelationTypes: raw?.custom_relation_types ?? [],
1603
+ maxCustomTypes: raw?.max_custom_types ?? 32
1604
+ };
1605
+ }
761
1606
  export {
762
1607
  AuthError,
1608
+ ConnectionOAuthNamespace,
1609
+ ConnectionsNamespace,
763
1610
  ControlPlaneClient,
1611
+ GoogleDriveNamespace,
1612
+ GranolaNamespace,
1613
+ IntegrationsNamespace,
764
1614
  MemorySyncClient,
765
1615
  MemorySyncError,
766
1616
  NotFoundError,
1617
+ ObjectsNamespace,
1618
+ ProvidersNamespace,
767
1619
  RateLimitError,
1620
+ S3Namespace,
768
1621
  ServerError,
769
- ValidationError
1622
+ SlackNamespace,
1623
+ SyncJobsNamespace,
1624
+ ValidationError,
1625
+ WebCrawlerNamespace
770
1626
  };
771
1627
  //# sourceMappingURL=index.mjs.map