memorysync-sdk 1.3.0 → 1.5.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
@@ -46,6 +46,9 @@ var V1 = "/api/v1/integrations";
46
46
  function seg(value) {
47
47
  return encodeURIComponent(String(value));
48
48
  }
49
+ function asItem(value, key) {
50
+ return typeof value === "string" ? { [key]: value } : value;
51
+ }
49
52
  var Namespace = class {
50
53
  constructor(request) {
51
54
  this.req = request;
@@ -65,10 +68,22 @@ var SlackNamespace = class extends Namespace {
65
68
  channels(connectionId) {
66
69
  return this.req("GET", `${V2}/connections/${seg(connectionId)}/slack/channels`);
67
70
  }
68
- /** Select channels for syncing. */
69
- addChannels(connectionId, channelIds) {
71
+ /**
72
+ * Select channels for syncing.
73
+ *
74
+ * Accepts bare channel ids, which is the common case, or objects carrying the
75
+ * name and type across so the server does not have to look them up again:
76
+ *
77
+ * ```ts
78
+ * await client.connections.slack.addChannels("c1", ["C0123", "C0456"]);
79
+ * await client.connections.slack.addChannels("c1", [
80
+ * { id: "C0123", name: "support", is_private: false },
81
+ * ]);
82
+ * ```
83
+ */
84
+ addChannels(connectionId, channels) {
70
85
  return this.req("POST", `${V2}/connections/${seg(connectionId)}/slack/channels`, {
71
- body: { channel_ids: channelIds }
86
+ body: { channels: channels.map((c) => asItem(c, "id")) }
72
87
  });
73
88
  }
74
89
  /** Stop syncing one channel. */
@@ -135,22 +150,42 @@ var S3Namespace = class extends Namespace {
135
150
  prefixes(connectionId) {
136
151
  return this.req("GET", `${V2}/connections/${seg(connectionId)}/s3/prefixes`);
137
152
  }
138
- /** Select prefixes for syncing. */
153
+ /**
154
+ * Select prefixes for syncing.
155
+ *
156
+ * Accepts bare prefixes, or objects carrying `bucket` and `label`:
157
+ *
158
+ * ```ts
159
+ * await client.connections.s3.addPrefixes("c1", ["handbook/", "policies/"]);
160
+ * await client.connections.s3.addPrefixes("c1", [
161
+ * { prefix: "handbook/", label: "Handbook" },
162
+ * ]);
163
+ * ```
164
+ *
165
+ * An empty string means the bucket root. The bucket defaults to the one the
166
+ * connection's credentials were validated against, and the API rejects any
167
+ * other bucket rather than indexing one nobody proved access to.
168
+ */
139
169
  addPrefixes(connectionId, prefixes) {
140
170
  return this.req("POST", `${V2}/connections/${seg(connectionId)}/s3/prefixes`, {
141
- body: { prefixes }
171
+ body: { prefixes: prefixes.map((p) => asItem(p, "prefix")) }
142
172
  });
143
173
  }
144
174
  /**
145
- * Stop syncing the given prefixes.
175
+ * Revoke one prefix approval, optionally purging what it produced.
176
+ *
177
+ * The prefix travels as a query parameter, not in the body and not as a path
178
+ * segment: prefixes contain slashes, which a path segment cannot carry
179
+ * unambiguously, and this endpoint reads no body at all.
146
180
  *
147
- * The prefixes travel in the body rather than the path because they contain
148
- * slashes, which is why this DELETE carries one.
181
+ * Pass `purge: true` to also delete the memories already derived from the
182
+ * prefix. The default leaves them in place, so revoking an approval does not
183
+ * silently destroy knowledge.
149
184
  */
150
- removePrefixes(connectionId, prefixes) {
151
- return this.req("DELETE", `${V2}/connections/${seg(connectionId)}/s3/prefixes`, {
152
- body: { prefixes }
153
- });
185
+ removePrefix(connectionId, prefix = "", options = {}) {
186
+ const query = { prefix, purge: options.purge ?? false };
187
+ if (options.bucket !== void 0) query.bucket = options.bucket;
188
+ return this.req("DELETE", `${V2}/connections/${seg(connectionId)}/s3/prefixes`, { query });
154
189
  }
155
190
  /** Keys and patterns this connection will never sync. */
156
191
  exclusionPolicy(connectionId) {
@@ -205,9 +240,18 @@ var GranolaNamespace = class extends Namespace {
205
240
  linkIdentity(connectionId, body) {
206
241
  return this.req("POST", `${V2}/connections/${seg(connectionId)}/granola/identities/link`, { body });
207
242
  }
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 });
243
+ /**
244
+ * Re-run identity matching for this connection.
245
+ *
246
+ * Takes no arguments: the route reads no body and re-matches the whole roster.
247
+ * `body` is kept optional only so a forward-compatible field can be passed
248
+ * once the route grows one.
249
+ */
250
+ relinkIdentity(connectionId, body = {}) {
251
+ const hasFields = Object.keys(body).length > 0;
252
+ return this.req("POST", `${V2}/connections/${seg(connectionId)}/granola/identities/relink`, {
253
+ body: hasFields ? body : void 0
254
+ });
211
255
  }
212
256
  /** Effective Granola settings for this connection. */
213
257
  settings(connectionId) {
@@ -228,7 +272,9 @@ var ConnectionOAuthNamespace = class extends Namespace {
228
272
  * back — not your backend. Poll {@link status} to find out how it went.
229
273
  */
230
274
  initiate(provider, body = {}) {
231
- return this.req("POST", `${V2}/oauth/initiate`, { body: { provider, ...body } });
275
+ return this.req("POST", `${V2}/oauth/initiate`, {
276
+ body: { provider_id: provider, ...body }
277
+ });
232
278
  }
233
279
  /** Where an in-flight OAuth connection got to. */
234
280
  status(query) {
@@ -253,15 +299,21 @@ var ConnectionsNamespace = class extends Namespace {
253
299
  return this.req("GET", `${V2}/connections/${seg(connectionId)}`);
254
300
  }
255
301
  /** Connect a provider that authenticates with an API key or bot token. */
302
+ /**
303
+ * Connect a provider that authenticates with an API key or bot token.
304
+ *
305
+ * The wire field is `provider_id`; the argument is named `provider` because
306
+ * that is what the rest of this namespace calls it.
307
+ */
256
308
  createWithApiKey(provider, apiKey, body = {}) {
257
309
  return this.req("POST", `${V2}/connections/api-key`, {
258
- body: { provider, api_key: apiKey, ...body }
310
+ body: { provider_id: provider, api_key: apiKey, ...body }
259
311
  });
260
312
  }
261
313
  /** Connect a provider that needs a credential bundle, such as S3 keys. */
262
314
  createWithCredentials(provider, credentials, body = {}) {
263
315
  return this.req("POST", `${V2}/connections/credentials`, {
264
- body: { provider, credentials, ...body }
316
+ body: { provider_id: provider, credentials, ...body }
265
317
  });
266
318
  }
267
319
  /** Change a connection's name, schedule or settings. */
@@ -480,7 +532,7 @@ var IntegrationsNamespace = class extends Namespace {
480
532
  };
481
533
 
482
534
  // src/control-plane.ts
483
- var SDK_VERSION = "1.1.1";
535
+ var SDK_VERSION = "1.5.0";
484
536
  function safeJson(text) {
485
537
  try {
486
538
  return JSON.parse(text);
@@ -557,17 +609,51 @@ function boundedInteger(value, name, minimum, maximum) {
557
609
  throw new ValidationError(`${name} must be an integer between ${minimum} and ${maximum}`);
558
610
  }
559
611
  }
560
- function nonNegativeInteger(value, name) {
561
- if (!Number.isInteger(value) || value < 0) {
562
- throw new ValidationError(`${name} must be a non-negative integer`);
563
- }
564
- }
565
612
  function nonEmptyStrings(values, name) {
566
613
  if (!Array.isArray(values) || values.length === 0 || values.some((value) => typeof value !== "string" || !value.trim())) {
567
614
  throw new ValidationError(`${name} must contain at least one non-empty string`);
568
615
  }
569
616
  }
617
+ function projectName(value) {
618
+ nonEmpty(value, "name");
619
+ if (value.length > 200) throw new ValidationError("name may contain at most 200 characters");
620
+ }
621
+ function pathId(value, name, minimum = 1, maximum) {
622
+ nonEmpty(value, name);
623
+ const trimmed = value.trim();
624
+ if (trimmed.length < minimum || maximum !== void 0 && trimmed.length > maximum) {
625
+ const range = maximum === void 0 ? `at least ${minimum}` : `between ${minimum} and ${maximum}`;
626
+ throw new ValidationError(`${name} must contain ${range} characters`);
627
+ }
628
+ return encodeURIComponent(trimmed);
629
+ }
630
+ function validateWebhookRetryConfig(config) {
631
+ if (config.maxRetries !== void 0) boundedInteger(config.maxRetries, "maxRetries", 1, 10);
632
+ if (config.initialDelaySeconds !== void 0) boundedInteger(config.initialDelaySeconds, "initialDelaySeconds", 1, 60);
633
+ if (config.maxDelaySeconds !== void 0) boundedInteger(config.maxDelaySeconds, "maxDelaySeconds", 60, 86400);
634
+ if (config.backoffMultiplier !== void 0 && (!Number.isFinite(config.backoffMultiplier) || config.backoffMultiplier < 1 || config.backoffMultiplier > 5)) {
635
+ throw new ValidationError("backoffMultiplier must be between 1 and 5");
636
+ }
637
+ if (config.retryStatusCodes !== void 0 && (!Array.isArray(config.retryStatusCodes) || config.retryStatusCodes.length === 0 || config.retryStatusCodes.some((value) => typeof value !== "string" || value.trim().length === 0))) {
638
+ throw new ValidationError("retryStatusCodes must contain at least one non-empty string");
639
+ }
640
+ }
641
+ function validateWebhookSignatureConfig(config) {
642
+ if (config.algorithm !== void 0 && config.algorithm !== "hmac-sha256" && config.algorithm !== "hmac-sha512") {
643
+ throw new ValidationError("algorithm must be 'hmac-sha256' or 'hmac-sha512'");
644
+ }
645
+ for (const [name, value] of [["headerName", config.headerName], ["timestampHeader", config.timestampHeader]]) {
646
+ if (value !== void 0 && value.trim().length === 0) {
647
+ throw new ValidationError(`${name} must be a non-empty string`);
648
+ }
649
+ if (value !== void 0 && value.length > 64) {
650
+ throw new ValidationError(`${name} may contain at most 64 characters`);
651
+ }
652
+ }
653
+ if (config.toleranceSeconds !== void 0) boundedInteger(config.toleranceSeconds, "toleranceSeconds", 60, 3600);
654
+ }
570
655
  function webhookRetryConfig(config) {
656
+ validateWebhookRetryConfig(config);
571
657
  const wire = {};
572
658
  if (config.enabled !== void 0) wire.enabled = config.enabled;
573
659
  if (config.maxRetries !== void 0) wire.max_retries = config.maxRetries;
@@ -578,6 +664,7 @@ function webhookRetryConfig(config) {
578
664
  return wire;
579
665
  }
580
666
  function webhookSignatureConfig(config) {
667
+ validateWebhookSignatureConfig(config);
581
668
  const wire = {};
582
669
  if (config.algorithm !== void 0) wire.algorithm = config.algorithm;
583
670
  if (config.headerName !== void 0) wire.header_name = config.headerName;
@@ -585,6 +672,19 @@ function webhookSignatureConfig(config) {
585
672
  if (config.toleranceSeconds !== void 0) wire.tolerance_seconds = config.toleranceSeconds;
586
673
  return wire;
587
674
  }
675
+ function exportFilters(filters) {
676
+ const wire = {};
677
+ if (filters.q !== void 0) wire.q = filters.q;
678
+ if (filters.userId !== void 0) wire.user_id = filters.userId;
679
+ if (filters.isSummary !== void 0) wire.is_summary = filters.isSummary;
680
+ if (filters.tier !== void 0) wire.tier = filters.tier;
681
+ if (filters.source !== void 0) wire.source = filters.source;
682
+ if (filters.timeRange !== void 0) wire.time_range = filters.timeRange;
683
+ if (filters.dateFrom !== void 0) wire.date_from = filters.dateFrom;
684
+ if (filters.dateTo !== void 0) wire.date_to = filters.dateTo;
685
+ if (filters.includeSoftDeleted !== void 0) wire.include_soft_deleted = filters.includeSoftDeleted;
686
+ return wire;
687
+ }
588
688
  function validateWebhook(name, url, events) {
589
689
  nonEmpty(name, "name");
590
690
  if (name.length > 128) throw new ValidationError("name may contain at most 128 characters");
@@ -724,20 +824,6 @@ var ControlPlaneClient = class {
724
824
  async getCurrentPlan(options = {}) {
725
825
  return this.request("GET", "/org/billing/current-plan", options);
726
826
  }
727
- async listTeamMembers(options = {}) {
728
- return this.request("GET", "/admin/team/members", options);
729
- }
730
- async suspendTeamMember(memberId, options = {}) {
731
- positiveId(memberId, "memberId");
732
- return this.request("PATCH", `/admin/team/members/${memberId}`, {
733
- ...options,
734
- body: { status: "suspended" }
735
- });
736
- }
737
- async removeTeamMember(memberId, options = {}) {
738
- positiveId(memberId, "memberId");
739
- return this.request("DELETE", `/admin/team/members/${memberId}`, options);
740
- }
741
827
  async listSessions(options = {}) {
742
828
  return this.request("GET", "/auth/sessions", options);
743
829
  }
@@ -745,43 +831,6 @@ var ControlPlaneClient = class {
745
831
  positiveId(sessionId, "sessionId");
746
832
  return this.request("POST", `/auth/sessions/${sessionId}/revoke`, options);
747
833
  }
748
- async listAuditEvents(query = {}, options = {}) {
749
- if (query.limit !== void 0) boundedInteger(query.limit, "limit", 1, 200);
750
- if (query.cursor !== void 0) nonNegativeInteger(query.cursor, "cursor");
751
- if (query.skip !== void 0) nonNegativeInteger(query.skip, "skip");
752
- if (query.sortDirection !== void 0 && query.sortDirection !== "asc" && query.sortDirection !== "desc") {
753
- throw new ValidationError("sortDirection must be 'asc' or 'desc'");
754
- }
755
- const path = "/admin/audit-logs" + queryString({
756
- limit: query.limit,
757
- cursor: query.cursor,
758
- skip: query.skip,
759
- sort: query.sortDirection,
760
- tenant_id: query.tenantId,
761
- actor: query.actor,
762
- actor_email: query.actorEmail,
763
- ip: query.ip,
764
- action: query.action,
765
- resource_type: query.resourceType,
766
- resource_id: query.resourceId,
767
- severity: query.severity,
768
- category: query.category,
769
- start: query.start,
770
- end: query.end,
771
- success: query.success,
772
- source: query.source,
773
- ingest_method: query.ingestMethod,
774
- search: query.search,
775
- include_stats: query.includeStats
776
- });
777
- const raw = await this.request("GET", path, options);
778
- return {
779
- events: raw.logs ?? [],
780
- nextCursor: raw.nextCursor ?? null,
781
- stats: raw.stats ?? null,
782
- sort: raw.sort ?? query.sortDirection ?? "desc"
783
- };
784
- }
785
834
  async listIntegrations(query = {}, options = {}) {
786
835
  if (query.category !== void 0) nonEmpty(query.category, "category");
787
836
  const path = "/api/v1/integrations/catalog" + queryString({ category: query.category });
@@ -797,23 +846,36 @@ var ControlPlaneClient = class {
797
846
  async listOrganizations(options = {}) {
798
847
  return this.request("GET", "/organizations", options);
799
848
  }
800
- async listOrganizationMembers(options = {}) {
801
- return this.listTeamMembers(options);
802
- }
803
- async getOrganizationSettings(query = {}, options = {}) {
804
- if (query.tenantId !== void 0) nonEmpty(query.tenantId, "tenantId");
805
- const path = "/admin/tenant-settings" + queryString({ tenant_id: query.tenantId });
806
- return this.request("GET", path, options);
807
- }
808
849
  async listProjects(options = {}) {
809
850
  return this.request("GET", "/org/projects", options);
810
851
  }
852
+ async createProject(request, options = {}) {
853
+ projectName(request.name);
854
+ return this.request("POST", "/org/projects", { ...options, body: { name: request.name } });
855
+ }
856
+ async renameProject(projectId, request, options = {}) {
857
+ const encodedId = pathId(projectId, "projectId");
858
+ projectName(request.name);
859
+ return this.request("PATCH", `/org/projects/${encodedId}`, { ...options, body: { name: request.name } });
860
+ }
861
+ async archiveProject(projectId, options = {}) {
862
+ return this.request("POST", `/org/projects/${pathId(projectId, "projectId")}/archive`, options);
863
+ }
864
+ async unarchiveProject(projectId, options = {}) {
865
+ return this.request("POST", `/org/projects/${pathId(projectId, "projectId")}/unarchive`, options);
866
+ }
867
+ async deleteProject(projectId, options = {}) {
868
+ return this.request("DELETE", `/org/projects/${pathId(projectId, "projectId")}`, options);
869
+ }
811
870
  async createWebhook(request, options = {}) {
812
871
  validateWebhook(request.name, request.url, request.events);
813
872
  if (request.description !== void 0 && request.description.length > 500) {
814
873
  throw new ValidationError("description may contain at most 500 characters");
815
874
  }
816
- if (request.projectId !== void 0) nonEmpty(request.projectId, "projectId");
875
+ if (request.projectId !== void 0) {
876
+ nonEmpty(request.projectId, "projectId");
877
+ if (request.projectId.length > 64) throw new ValidationError("projectId may contain at most 64 characters");
878
+ }
817
879
  if (options.projectId !== void 0) nonEmpty(options.projectId, "projectId override");
818
880
  if (request.projectId && options.projectId && request.projectId.trim() !== options.projectId.trim()) {
819
881
  throw new ValidationError("request projectId and options projectId must match");
@@ -832,6 +894,28 @@ var ControlPlaneClient = class {
832
894
  async listWebhooks(options = {}) {
833
895
  return this.request("GET", "/org/webhooks", options);
834
896
  }
897
+ async getWebhook(endpointId, options = {}) {
898
+ positiveId(endpointId, "endpointId");
899
+ return this.request("GET", `/org/webhooks/${endpointId}`, options);
900
+ }
901
+ async getWebhookEventTypes(options = {}) {
902
+ return this.request("GET", "/org/webhooks/event-types", options);
903
+ }
904
+ async getWebhookHealth(options = {}) {
905
+ return this.request("GET", "/org/webhooks/health", options);
906
+ }
907
+ async pauseWebhook(endpointId, options = {}) {
908
+ positiveId(endpointId, "endpointId");
909
+ return this.request("POST", `/org/webhooks/${endpointId}/pause`, options);
910
+ }
911
+ async resumeWebhook(endpointId, options = {}) {
912
+ positiveId(endpointId, "endpointId");
913
+ return this.request("POST", `/org/webhooks/${endpointId}/resume`, options);
914
+ }
915
+ async rotateWebhookSecret(endpointId, options = {}) {
916
+ positiveId(endpointId, "endpointId");
917
+ return this.request("POST", `/org/webhooks/${endpointId}/rotate-secret`, options);
918
+ }
835
919
  async updateWebhook(endpointId, request, options = {}) {
836
920
  positiveId(endpointId, "endpointId");
837
921
  const body = {};
@@ -892,9 +976,7 @@ var ControlPlaneClient = class {
892
976
  async listWebhookDeliveries(endpointId, query = {}, options = {}) {
893
977
  positiveId(endpointId, "endpointId");
894
978
  if (query.page !== void 0) positiveId(query.page, "page");
895
- if (query.pageSize !== void 0 && (!Number.isInteger(query.pageSize) || query.pageSize < 1 || query.pageSize > 100)) {
896
- throw new ValidationError("pageSize must be an integer between 1 and 100");
897
- }
979
+ if (query.pageSize !== void 0) boundedInteger(query.pageSize, "pageSize", 1, 100);
898
980
  if (query.status !== void 0) nonEmpty(query.status, "status");
899
981
  const path = `/org/webhooks/${endpointId}/deliveries` + queryString({
900
982
  page: query.page,
@@ -903,10 +985,62 @@ var ControlPlaneClient = class {
903
985
  });
904
986
  return this.request("GET", path, options);
905
987
  }
988
+ async getLatestWebhookDelivery(endpointId, options = {}) {
989
+ positiveId(endpointId, "endpointId");
990
+ return this.request("GET", `/org/webhooks/${endpointId}/deliveries/latest`, options);
991
+ }
992
+ async listRecentWebhookDeliveries(query = {}, options = {}) {
993
+ if (query.page !== void 0) positiveId(query.page, "page");
994
+ if (query.pageSize !== void 0) boundedInteger(query.pageSize, "pageSize", 1, 100);
995
+ if (query.endpointId !== void 0) positiveId(query.endpointId, "endpointId");
996
+ if (query.status !== void 0) nonEmpty(query.status, "status");
997
+ const path = "/org/webhooks/deliveries/recent" + queryString({
998
+ page: query.page,
999
+ page_size: query.pageSize,
1000
+ endpoint_id: query.endpointId,
1001
+ status_filter: query.status
1002
+ });
1003
+ return this.request("GET", path, options);
1004
+ }
1005
+ async getWebhookDelivery(deliveryId, options = {}) {
1006
+ positiveId(deliveryId, "deliveryId");
1007
+ return this.request("GET", `/org/webhooks/deliveries/${deliveryId}`, options);
1008
+ }
1009
+ async retryWebhookDelivery(deliveryId, options = {}) {
1010
+ positiveId(deliveryId, "deliveryId");
1011
+ return this.request("POST", `/org/webhooks/deliveries/${deliveryId}/retry`, options);
1012
+ }
1013
+ async createExport(request, options = {}) {
1014
+ const format = request.format ?? "csv";
1015
+ const scope = request.scope ?? "filtered";
1016
+ if (format !== "csv" && format !== "jsonl") throw new ValidationError("format must be 'csv' or 'jsonl'");
1017
+ if (scope !== "filtered" && scope !== "all" && scope !== "date_range") {
1018
+ throw new ValidationError("scope must be 'filtered', 'all', or 'date_range'");
1019
+ }
1020
+ const body = { format, scope };
1021
+ if (request.filters !== void 0) body.filters = request.filters === null ? null : exportFilters(request.filters);
1022
+ return this.request("POST", "/exports", { ...options, body });
1023
+ }
1024
+ async listExports(query = {}, options = {}) {
1025
+ if (query.limit !== void 0) boundedInteger(query.limit, "limit", 1, 100);
1026
+ return this.request("GET", "/exports" + queryString({ limit: query.limit }), options);
1027
+ }
1028
+ async getExport(jobId, options = {}) {
1029
+ return this.request("GET", `/exports/${pathId(jobId, "jobId", 8, 64)}`, options);
1030
+ }
1031
+ async cancelExport(jobId, options = {}) {
1032
+ return this.request("POST", `/exports/${pathId(jobId, "jobId", 8, 64)}/cancel`, options);
1033
+ }
1034
+ async retryExport(jobId, options = {}) {
1035
+ return this.request("POST", `/exports/${pathId(jobId, "jobId", 8, 64)}/retry`, options);
1036
+ }
1037
+ async getExportDownloadUrl(jobId, options = {}) {
1038
+ return this.request("GET", `/exports/${pathId(jobId, "jobId", 8, 64)}/download-url`, options);
1039
+ }
906
1040
  };
907
1041
 
908
1042
  // src/index.ts
909
- var SDK_VERSION2 = "1.3.0";
1043
+ var SDK_VERSION2 = "1.5.0";
910
1044
  function camelToSnakeKey(key) {
911
1045
  return key.replace(/([A-Z])/g, "_$1").toLowerCase();
912
1046
  }