@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/README.md +38 -0
- package/dist/openapi/medal-social.openapi.json +686 -0
- package/dist/pilot/index.d.mts +2 -2
- package/dist/pilot/index.d.ts +2 -2
- package/dist/src/index.d.mts +230 -3
- package/dist/src/index.d.ts +230 -3
- package/dist/src/index.js +144 -19
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.mjs +143 -19
- package/dist/src/index.mjs.map +1 -1
- package/dist/src/openapi.generated.d.mts +473 -0
- package/dist/src/openapi.generated.d.ts +473 -0
- package/dist/src/openapi.generated.js.map +1 -1
- package/openapi/medal-social.openapi.yaml +446 -0
- package/package.json +1 -1
- package/skills/client/SKILL.md +2 -0
- package/skills/resources/SKILL.md +50 -2
package/README.md
CHANGED
|
@@ -272,6 +272,44 @@ if (summary.can_reschedule) {
|
|
|
272
272
|
|
|
273
273
|
`update(id, input)` requires at least one of `notes` / `internal_notes`; `update(id, {})` is a compile error, matching the API's own 400.
|
|
274
274
|
|
|
275
|
+
### Customer portal
|
|
276
|
+
|
|
277
|
+
Self-service for the workspace's own customers: they sign in with an e-mailed one-time code, then see and change their profile, list their bookings, export their data, or erase their account. The API key needs `read:portal` and `write:portal`.
|
|
278
|
+
|
|
279
|
+
The session token is a **bearer credential for one contact**. Your site's server exchanges the code for it and keeps it in an **HttpOnly cookie on the site's own domain** — never hand it to the browser, and never let the browser call Medal directly. Session-bound methods take the token as their first argument and send it as `X-Portal-Session`.
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
// 1. Send the code. Always { status: 'sent' } — enumeration-safe, so "sent" does
|
|
283
|
+
// not confirm the address belongs to a contact.
|
|
284
|
+
await medal.portal.login.start({ email: 'ida@example.com', locale: 'nb' });
|
|
285
|
+
|
|
286
|
+
// 2. Exchange the code the customer typed. Wrong, burned and expired codes all
|
|
287
|
+
// answer 401 PORTAL_CODE_INVALID.
|
|
288
|
+
const { data: session } = await medal.portal.login.verify({ email: 'ida@example.com', code: '123456' });
|
|
289
|
+
// -> set an HttpOnly, Secure, SameSite cookie holding session.session_token,
|
|
290
|
+
// expiring at session.expires_at (Unix ms)
|
|
291
|
+
|
|
292
|
+
// 3. Session-bound calls, from your server, with the token read back from the cookie
|
|
293
|
+
const { data: me } = await medal.portal.me(session.session_token);
|
|
294
|
+
const { data: bookings } = await medal.portal.myBookings(session.session_token);
|
|
295
|
+
// bookings.upcoming[i].manage_token is set while the booking is still manageable —
|
|
296
|
+
// it opens your site's manage page (medal.bookings.manage.*); past bookings carry null
|
|
297
|
+
await medal.portal.updateMe(session.session_token, {
|
|
298
|
+
phone: '+4790000000',
|
|
299
|
+
family: [{ name: 'Ola', birth_year: 2018 }], // replaces the whole list
|
|
300
|
+
marketing_consent: true, // recorded as a marketing_email consent, source 'portal'
|
|
301
|
+
});
|
|
302
|
+
const { data: exported } = await medal.portal.exportMyData(session.session_token); // GDPR Art. 15, synchronous
|
|
303
|
+
await medal.portal.logout(session.session_token); // 204 — revokes this session only
|
|
304
|
+
// …or, when the customer asks to be forgotten (terminal — the session is revoked, a later
|
|
305
|
+
// logout() would answer 401 PORTAL_SESSION_INVALID):
|
|
306
|
+
await medal.portal.deleteMe(session.session_token); // GDPR Art. 17 — 204
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`401 PORTAL_SESSION_REQUIRED` (header missing) and `401 PORTAL_SESSION_INVALID` (unknown, expired or revoked) both mean "sign in again" — clear the cookie and send the customer back to step 1. `403 FORBIDDEN` means the key lacks the portal scopes; `429 RATE_LIMITED` applies per address and per caller on `login.start`.
|
|
310
|
+
|
|
311
|
+
None of the portal calls carries an `Idempotency-Key`: the two login routes cannot duplicate anything, and the session routes are either reads or terminal.
|
|
312
|
+
|
|
275
313
|
### GDPR
|
|
276
314
|
|
|
277
315
|
```ts
|