@mymehq/sdk 4.3.0 → 4.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.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { MergeStrategy, ConflictSnapshot, MergePolicy, ItemState, Tier, Item, CreateItemInput, PaginatedResult, ItemWithMetadata, Version, Edge, Metadata, SearchResult, CreateEdgeInput, EdgeTypeSchema, TypeSchema, CreateKeyInput, ApiKey, UpdateKeyInput, CreateWebhookInput, Webhook, UpdateWebhookInput, WebhookDelivery, TenantConfig } from '@mymehq/shared';
1
+ import { MergeStrategy, ConflictSnapshot, MergePolicy, ItemState, Tier, Item, CreateItemInput, PaginatedResult, ItemWithMetadata, Version, Edge, Metadata, SearchResult, CreateEdgeInput, EdgeTypeSchema, TypeSchema, CreateKeyInput, ApiKey, UpdateKeyInput, CreateWebhookInput, Webhook, UpdateWebhookInput, WebhookDelivery, ConnectionInstallResult, ConnectionUninstallResult, TenantConfig } from '@mymehq/shared';
2
2
  export { ApiKey, ConflictSnapshot, CreateItemInput, CreateKeyInput, Item, ItemState, MergePolicy, MergeStrategy, Metadata, PaginatedResult, SearchResult, TypeSchema, UpdateKeyInput, Version } from '@mymehq/shared';
3
3
 
4
4
  /**
@@ -352,6 +352,29 @@ declare class MymeClient {
352
352
  * targets with the new item as source. */
353
353
  edges?: Record<string, string[]>;
354
354
  }) => Promise<Item>;
355
+ /**
356
+ * Create-or-update an item, surfacing whether the server resolved as a
357
+ * fresh create (HTTP 201) or a natural-key match update (HTTP 200).
358
+ *
359
+ * `POST /items` accepts a `(source, source_id)` pair as a stable
360
+ * natural key (T-038): a second POST with the same pair updates the
361
+ * existing row in place rather than 409ing. The wire shape returned
362
+ * is `{ item }` regardless — the only signal of "created vs updated"
363
+ * is the HTTP status code, which `transport.request` consumes
364
+ * internally. This method threads the status out so callers can
365
+ * surface the distinction (e.g. CLI `Created.` vs `Updated
366
+ * (natural-key match).`).
367
+ *
368
+ * Use `items.create` when the caller does not need the distinction —
369
+ * the wire shape is identical.
370
+ */
371
+ upsert: (input: CreateItemInput & {
372
+ /** Atomic edges payload, same semantics as `items.create`. */
373
+ edges?: Record<string, string[]>;
374
+ }) => Promise<{
375
+ item: Item;
376
+ created: boolean;
377
+ }>;
355
378
  get: (id: string) => Promise<Item>;
356
379
  list: (filters?: ListFilters) => Promise<PaginatedResult<Item>>;
357
380
  listWithMetadata: (filters?: Omit<ListFilters, "include">) => Promise<PaginatedResult<ItemWithMetadata>>;
@@ -526,6 +549,50 @@ declare class MymeClient {
526
549
  limit?: number;
527
550
  }) => Promise<WebhookDelivery[]>;
528
551
  };
552
+ /**
553
+ * Connection management. The `system.connection` items themselves are
554
+ * still managed via `client.items` (list, get, transition); this
555
+ * namespace adds the orchestrated lifecycle operations that don't fit
556
+ * the generic items surface — specifically `uninstall`, which requires
557
+ * a multi-step server-side teardown across credentials, tokens, and
558
+ * inbound subscriptions.
559
+ *
560
+ * Convenience filters for listing connections (by `integration_ref`,
561
+ * `state`, etc.) live on `client.items.list({ type: "system.connection",
562
+ * ... })`. The CLI's `my connections` tree wraps both.
563
+ */
564
+ readonly connections: {
565
+ /**
566
+ * JSON install of an Integration manifest — server-side sibling of
567
+ * the browser consent flow at `POST /integrations/:id/install`.
568
+ * Skips the HTML consent screen so operators and tooling can install
569
+ * connections non-interactively. Admin-only; tenant admins install
570
+ * into their own tenant scope.
571
+ *
572
+ * `integration_id` references a `system.integration` item (registered
573
+ * via `POST /integrations`). `label` is optional — the server
574
+ * defaults to `${manifest_name} ${manifest_version}` when omitted.
575
+ * Returns the new connection id, the seed runtime credential id,
576
+ * and the `system.activity` row id from the install pipeline.
577
+ */
578
+ install: (input: {
579
+ integration_id: string;
580
+ label?: string;
581
+ }) => Promise<ConnectionInstallResult>;
582
+ /**
583
+ * Orchestrated uninstall of an `external-service-connector`
584
+ * connection. Revokes runtime credentials, deletes upstream OAuth
585
+ * tokens, revokes active leased tokens, disables inbound webhook
586
+ * subscriptions, transitions the system.connection state to
587
+ * `revoked`, and emits a `system.activity` row. Audit-logged.
588
+ *
589
+ * Idempotent at the artefact level — revoking already-revoked
590
+ * tokens is a no-op — but rejects with 400 when the connection
591
+ * itself is already in state `revoked`. Admin-only; tenant admins
592
+ * can uninstall connections in their own tenant scope.
593
+ */
594
+ uninstall: (id: string) => Promise<ConnectionUninstallResult>;
595
+ };
529
596
  /** Tenant-scoped configuration. Controls feed-tier retention per type
530
597
  * and the three optional schema-enforcement levers (TSC42 §5). All
531
598
  * endpoints are admin-only. */
package/dist/index.js CHANGED
@@ -85,15 +85,41 @@ var HttpTransport = class {
85
85
  return `Bearer ${token}`;
86
86
  }
87
87
  async request(method, path, options) {
88
+ const { data } = await this.requestWithStatus(method, path, options);
89
+ return data;
90
+ }
91
+ /**
92
+ * Like {@link request}, but additionally surfaces the HTTP response
93
+ * status so callers can branch on 200 vs 201 (or any other 2xx). Used
94
+ * by `client.items.upsert` to distinguish a fresh create (201) from a
95
+ * natural-key match update (200) — `request<T>` consumes the status
96
+ * internally so this sibling exists to thread it back out.
97
+ *
98
+ * Error behaviour matches {@link request}: non-2xx responses throw the
99
+ * appropriate typed `MymeError` subclass via `throwForError`, never
100
+ * resolve. 204 No Content resolves with `data: undefined as T` and
101
+ * `status: 204`.
102
+ *
103
+ * Internal — not part of the public SDK surface. The exported `MymeClient`
104
+ * keeps callers at the namespace-method level (`client.items.upsert`,
105
+ * etc.) so the transport's status-passing remains an implementation
106
+ * detail.
107
+ */
108
+ // T is used by the caller to type the response body, mirroring `request<T>`.
109
+ // The rule's "single use" heuristic doesn't account for callers explicitly
110
+ // providing the type arg — see `requestWithStatus<{ item: Item }>` in
111
+ // `client.items.upsert`.
112
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
113
+ async requestWithStatus(method, path, options) {
88
114
  const response = await this.rawRequest(method, path, options);
89
115
  if (response.status === 204) {
90
- return void 0;
116
+ return { data: void 0, status: 204 };
91
117
  }
92
118
  const body = await this.parseJson(response);
93
119
  if (!response.ok) {
94
120
  this.throwForError(response.status, body);
95
121
  }
96
- return body;
122
+ return { data: body, status: response.status };
97
123
  }
98
124
  /**
99
125
  * Like request(), but returns the conflict response instead of throwing
@@ -359,6 +385,26 @@ var MymeClient = class {
359
385
  );
360
386
  return res.item;
361
387
  },
388
+ /**
389
+ * Create-or-update an item, surfacing whether the server resolved as a
390
+ * fresh create (HTTP 201) or a natural-key match update (HTTP 200).
391
+ *
392
+ * `POST /items` accepts a `(source, source_id)` pair as a stable
393
+ * natural key (T-038): a second POST with the same pair updates the
394
+ * existing row in place rather than 409ing. The wire shape returned
395
+ * is `{ item }` regardless — the only signal of "created vs updated"
396
+ * is the HTTP status code, which `transport.request` consumes
397
+ * internally. This method threads the status out so callers can
398
+ * surface the distinction (e.g. CLI `Created.` vs `Updated
399
+ * (natural-key match).`).
400
+ *
401
+ * Use `items.create` when the caller does not need the distinction —
402
+ * the wire shape is identical.
403
+ */
404
+ upsert: async (input) => {
405
+ const { data, status } = await this.transport.requestWithStatus("POST", "/items", { body: input });
406
+ return { item: data.item, created: status === 201 };
407
+ },
362
408
  get: async (id) => {
363
409
  const res = await this.transport.request(
364
410
  "GET",
@@ -835,6 +881,59 @@ var MymeClient = class {
835
881
  return res.deliveries;
836
882
  }
837
883
  };
884
+ // ---- Connections ----
885
+ /**
886
+ * Connection management. The `system.connection` items themselves are
887
+ * still managed via `client.items` (list, get, transition); this
888
+ * namespace adds the orchestrated lifecycle operations that don't fit
889
+ * the generic items surface — specifically `uninstall`, which requires
890
+ * a multi-step server-side teardown across credentials, tokens, and
891
+ * inbound subscriptions.
892
+ *
893
+ * Convenience filters for listing connections (by `integration_ref`,
894
+ * `state`, etc.) live on `client.items.list({ type: "system.connection",
895
+ * ... })`. The CLI's `my connections` tree wraps both.
896
+ */
897
+ connections = {
898
+ /**
899
+ * JSON install of an Integration manifest — server-side sibling of
900
+ * the browser consent flow at `POST /integrations/:id/install`.
901
+ * Skips the HTML consent screen so operators and tooling can install
902
+ * connections non-interactively. Admin-only; tenant admins install
903
+ * into their own tenant scope.
904
+ *
905
+ * `integration_id` references a `system.integration` item (registered
906
+ * via `POST /integrations`). `label` is optional — the server
907
+ * defaults to `${manifest_name} ${manifest_version}` when omitted.
908
+ * Returns the new connection id, the seed runtime credential id,
909
+ * and the `system.activity` row id from the install pipeline.
910
+ */
911
+ install: async (input) => {
912
+ return this.transport.request(
913
+ "POST",
914
+ "/connections/install",
915
+ { body: input }
916
+ );
917
+ },
918
+ /**
919
+ * Orchestrated uninstall of an `external-service-connector`
920
+ * connection. Revokes runtime credentials, deletes upstream OAuth
921
+ * tokens, revokes active leased tokens, disables inbound webhook
922
+ * subscriptions, transitions the system.connection state to
923
+ * `revoked`, and emits a `system.activity` row. Audit-logged.
924
+ *
925
+ * Idempotent at the artefact level — revoking already-revoked
926
+ * tokens is a no-op — but rejects with 400 when the connection
927
+ * itself is already in state `revoked`. Admin-only; tenant admins
928
+ * can uninstall connections in their own tenant scope.
929
+ */
930
+ uninstall: async (id) => {
931
+ return this.transport.request(
932
+ "POST",
933
+ `/connections/${id}/uninstall`
934
+ );
935
+ }
936
+ };
838
937
  // ---- Tenants (admin) ----
839
938
  /** Tenant-scoped configuration. Controls feed-tier retention per type
840
939
  * and the three optional schema-enforcement levers (TSC42 §5). All
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mymehq/sdk",
3
- "version": "4.3.0",
3
+ "version": "4.5.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -20,7 +20,7 @@
20
20
  "dist"
21
21
  ],
22
22
  "dependencies": {
23
- "@mymehq/shared": "4.3.0"
23
+ "@mymehq/shared": "4.5.0"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^22.0.0",