@medalsocial/sdk 1.7.0 → 1.8.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/src/index.js CHANGED
@@ -35,6 +35,7 @@ __export(src_exports, {
35
35
  Helpdesk: () => Helpdesk,
36
36
  Medal: () => Medal,
37
37
  MedalApiError: () => MedalApiError,
38
+ Portal: () => Portal,
38
39
  Posts: () => Posts,
39
40
  Scan: () => Scan,
40
41
  WebhookVerificationError: () => WebhookVerificationError,
@@ -83,17 +84,21 @@ var BaseClient = class {
83
84
  this.config = config;
84
85
  }
85
86
  /** Execute an authenticated GET request and return the parsed JSON body. */
86
- async get(path, params) {
87
+ async get(path, params, options) {
87
88
  const url = this.buildUrl(path, params);
88
- return this.request(url, { method: "GET" });
89
+ return this.request(url, { method: "GET", headers: options?.headers });
89
90
  }
90
91
  /** Execute an authenticated POST request with a JSON body. */
91
92
  async post(path, body, options) {
92
- return this.request(this.buildUrl(path), {
93
- method: "POST",
94
- headers: this.writeHeaders(options),
95
- body: body !== void 0 ? JSON.stringify(body) : void 0
96
- });
93
+ return this.request(
94
+ this.buildUrl(path),
95
+ {
96
+ method: "POST",
97
+ headers: this.writeHeaders(options),
98
+ body: body !== void 0 ? JSON.stringify(body) : void 0
99
+ },
100
+ options?.retry
101
+ );
97
102
  }
98
103
  /**
99
104
  * Execute a POST that must never execute twice, guaranteeing an
@@ -120,21 +125,33 @@ var BaseClient = class {
120
125
  }
121
126
  /** Execute an authenticated PATCH request with a JSON body. */
122
127
  async patch(path, body, options) {
123
- return this.request(this.buildUrl(path), {
124
- method: "PATCH",
125
- headers: this.writeHeaders(options),
126
- body: JSON.stringify(body)
127
- });
128
+ return this.request(
129
+ this.buildUrl(path),
130
+ {
131
+ method: "PATCH",
132
+ headers: this.writeHeaders(options),
133
+ body: JSON.stringify(body)
134
+ },
135
+ options?.retry
136
+ );
128
137
  }
129
138
  /** Execute an authenticated DELETE request. */
130
139
  async delete(path, options) {
131
- return this.request(this.buildUrl(path), {
132
- method: "DELETE",
133
- headers: this.writeHeaders(options)
134
- });
140
+ return this.request(
141
+ this.buildUrl(path),
142
+ {
143
+ method: "DELETE",
144
+ headers: this.writeHeaders(options)
145
+ },
146
+ options?.retry
147
+ );
135
148
  }
136
149
  writeHeaders(options) {
137
- const headers = { "content-type": "application/json" };
150
+ const headers = {};
151
+ for (const [key, value] of Object.entries(options?.headers ?? {})) {
152
+ headers[key.toLowerCase()] = value;
153
+ }
154
+ headers["content-type"] = "application/json";
138
155
  if (options?.idempotencyKey) {
139
156
  headers["idempotency-key"] = options.idempotencyKey;
140
157
  }
@@ -154,8 +171,8 @@ var BaseClient = class {
154
171
  }
155
172
  return url.toString();
156
173
  }
157
- async request(url, init) {
158
- const maxAttempts = 3;
174
+ async request(url, init, retry = true) {
175
+ const maxAttempts = retry ? 3 : 1;
159
176
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
160
177
  const headers = new Headers(init.headers);
161
178
  headers.set("authorization", `Bearer ${this.config.token}`);
@@ -929,6 +946,111 @@ var Helpdesk = class {
929
946
  }
930
947
  };
931
948
 
949
+ // src/resources/portal.ts
950
+ function withSession(session) {
951
+ return { headers: { "x-portal-session": session } };
952
+ }
953
+ var ONCE = { retry: false };
954
+ var PortalLogin = class {
955
+ constructor(client) {
956
+ this.client = client;
957
+ }
958
+ client;
959
+ /**
960
+ * E-mail a one-time code to the address.
961
+ *
962
+ * Always 202 `{ status: "sent" }` — enumeration-safe: `"sent"` does not
963
+ * confirm that the address belongs to a contact. Rate-limited per address
964
+ * and per caller (`429 RATE_LIMITED`).
965
+ */
966
+ async start(input) {
967
+ return this.client.post("/api/v1/portal/login/start", input);
968
+ }
969
+ /**
970
+ * Exchange the e-mailed code for a session.
971
+ *
972
+ * `session_token` is a bearer credential for ONE contact — keep it in an
973
+ * HttpOnly cookie on the site's server. A wrong, burned or expired code all
974
+ * answer `401 PORTAL_CODE_INVALID`; the three are not distinguished, so the
975
+ * response is not an oracle for which codes exist.
976
+ */
977
+ async verify(input) {
978
+ return this.client.post("/api/v1/portal/login/verify", input, ONCE);
979
+ }
980
+ };
981
+ var Portal = class {
982
+ constructor(client) {
983
+ this.client = client;
984
+ this.login = new PortalLogin(client);
985
+ }
986
+ client;
987
+ /** E-mail one-time-code login: `start` sends the code, `verify` exchanges it. */
988
+ login;
989
+ /**
990
+ * Revoke the session. Resolves to `undefined` (the route answers 204).
991
+ *
992
+ * Not keyed: revoking twice reaches the same state — the second call answers
993
+ * `401 PORTAL_SESSION_INVALID`, which is the outcome you wanted anyway.
994
+ */
995
+ async logout(session) {
996
+ await this.client.post("/api/v1/portal/logout", void 0, {
997
+ ...withSession(session),
998
+ ...ONCE
999
+ });
1000
+ }
1001
+ /** The signed-in contact's own profile. */
1002
+ async me(session) {
1003
+ return this.client.get("/api/v1/portal/me", void 0, withSession(session));
1004
+ }
1005
+ /**
1006
+ * Update the signed-in contact's profile. Only the supplied fields change;
1007
+ * `phone: null` clears the number and `family` replaces the whole list.
1008
+ * `marketing_consent` records a `marketing_email` consent decision with
1009
+ * source `portal`. Returns the profile as it is after the change.
1010
+ */
1011
+ /**
1012
+ * A profile patch is not idempotency-keyed on the server and a `marketing_consent`
1013
+ * change records a dated consent event, so a retry after a committed-but-lost
1014
+ * response would repeat that event: sent exactly once, like the other writes.
1015
+ */
1016
+ async updateMe(session, patch) {
1017
+ return this.client.patch("/api/v1/portal/me", patch, { ...withSession(session), ...ONCE });
1018
+ }
1019
+ /**
1020
+ * The contact's bookings split into `upcoming` and `past`. An upcoming
1021
+ * booking that is still inside the workspace's policy windows carries
1022
+ * `manage_token` and `can_manage: true`; use the token to open the site's
1023
+ * manage page (`medal.bookings.manage.*`).
1024
+ */
1025
+ async myBookings(session) {
1026
+ return this.client.get("/api/v1/portal/me/bookings", void 0, withSession(session));
1027
+ }
1028
+ /**
1029
+ * Everything the workspace holds about the contact — profile, family,
1030
+ * consents and bookings — as one JSON document (GDPR Art. 15). Synchronous,
1031
+ * unlike `medal.gdpr.requestExport()`, which exports the whole workspace.
1032
+ *
1033
+ * Not keyed: a read-only snapshot, so a retried call costs nothing and
1034
+ * duplicates nothing.
1035
+ */
1036
+ async exportMyData(session) {
1037
+ return this.client.post("/api/v1/portal/me/export", void 0, withSession(session));
1038
+ }
1039
+ /**
1040
+ * Erase the contact (GDPR Art. 17). Resolves to `undefined` (the route
1041
+ * answers 204); the session is revoked as part of the deletion.
1042
+ *
1043
+ * Not keyed: deletion is terminal, so a retry meets a revoked session and
1044
+ * answers `401 PORTAL_SESSION_INVALID` rather than deleting anything else.
1045
+ */
1046
+ async deleteMe(session) {
1047
+ await this.client.post("/api/v1/portal/me/delete", void 0, {
1048
+ ...withSession(session),
1049
+ ...ONCE
1050
+ });
1051
+ }
1052
+ };
1053
+
932
1054
  // src/resources/posts.ts
933
1055
  var Posts = class {
934
1056
  constructor(client) {
@@ -1234,6 +1356,7 @@ var Medal = class {
1234
1356
  deals;
1235
1357
  gdpr;
1236
1358
  helpdesk;
1359
+ portal;
1237
1360
  posts;
1238
1361
  scan;
1239
1362
  webhooks;
@@ -1263,6 +1386,7 @@ var Medal = class {
1263
1386
  this.deals = new Deals(client);
1264
1387
  this.gdpr = new Gdpr(client);
1265
1388
  this.helpdesk = new Helpdesk(client, confirmer);
1389
+ this.portal = new Portal(client);
1266
1390
  this.posts = new Posts(client);
1267
1391
  this.scan = new Scan(client);
1268
1392
  this.webhooks = new Webhooks(client, confirmer);
@@ -1290,6 +1414,7 @@ var src_default = Medal;
1290
1414
  Helpdesk,
1291
1415
  Medal,
1292
1416
  MedalApiError,
1417
+ Portal,
1293
1418
  Posts,
1294
1419
  Scan,
1295
1420
  WebhookVerificationError,