@medalsocial/sdk 0.1.2 → 1.0.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.js CHANGED
@@ -20,122 +20,370 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- MedalSocialClient: () => MedalSocialClient,
23
+ BaseClient: () => BaseClient,
24
+ Contacts: () => Contacts,
25
+ Deals: () => Deals,
26
+ Emails: () => Emails,
27
+ Gdpr: () => Gdpr,
28
+ Medal: () => Medal,
29
+ MedalApiError: () => MedalApiError,
30
+ Posts: () => Posts,
31
+ Workspaces: () => Workspaces,
24
32
  default: () => index_default
25
33
  });
26
34
  module.exports = __toCommonJS(index_exports);
27
- var MedalSocialClient = class {
28
- baseUrl;
29
- auth;
30
- timeoutMs;
31
- userAgent;
32
- constructor(options) {
33
- this.baseUrl = (options.baseUrl ?? "https://api.medalsocial.com").replace(/\/$/, "");
34
- this.auth = options.auth;
35
- this.timeoutMs = options.timeoutMs ?? 3e4;
36
- this.userAgent = options.userAgent ?? "medal-social-sdk/0.1.0 (+https://github.com/Medal-Social/MedalSocial.git)";
37
- }
38
- // Public endpoints
39
- /** Create one or more leads */
40
- async createLead(items) {
41
- return this.post("/v1/leads", items);
42
- }
43
- /** Create a note attached to a contact by id */
44
- async createContactNote(input) {
45
- return this.post("/v1/contacts/notes", input);
46
- }
47
- /** Record a user’s cookie consent preferences */
48
- async createCookieConsent(input) {
49
- return this.post("/v1/cookie-consent", input);
50
- }
51
- /** Create an event signup with contact and event details */
52
- async createEventSignup(input) {
53
- return this.post("/v1/event-signup", input);
54
- }
55
- /** Create a free-form note for inbound messages */
56
- async createNote(input) {
57
- return this.post("/v1/notes", input);
58
- }
59
- /** Send a transactional email by template slug */
60
- async sendTransactionalEmail(input) {
61
- return this.post("/v1/send-transactional-email", input);
62
- }
63
- // Internal HTTP helpers
35
+
36
+ // src/types/common.ts
37
+ var MedalApiError = class extends Error {
38
+ status;
39
+ code;
40
+ details;
41
+ constructor(status, code, message, details) {
42
+ super(message);
43
+ this.name = "MedalApiError";
44
+ this.status = status;
45
+ this.code = code;
46
+ this.details = details;
47
+ }
48
+ };
49
+
50
+ // src/client.ts
51
+ var BaseClient = class {
52
+ config;
53
+ constructor(config) {
54
+ this.config = config;
55
+ }
56
+ async get(path, params) {
57
+ const url = this.buildUrl(path, params);
58
+ return this.request(url, { method: "GET" });
59
+ }
64
60
  async post(path, body) {
61
+ return this.request(this.buildUrl(path), {
62
+ method: "POST",
63
+ headers: { "content-type": "application/json" },
64
+ body: body !== void 0 ? JSON.stringify(body) : void 0
65
+ });
66
+ }
67
+ async patch(path, body) {
68
+ return this.request(this.buildUrl(path), {
69
+ method: "PATCH",
70
+ headers: { "content-type": "application/json" },
71
+ body: JSON.stringify(body)
72
+ });
73
+ }
74
+ async delete(path) {
75
+ return this.request(this.buildUrl(path), { method: "DELETE" });
76
+ }
77
+ buildUrl(path, params) {
78
+ const url = new URL(`${this.config.baseUrl}${path}`);
79
+ if (params) {
80
+ for (const [key, value] of Object.entries(params)) {
81
+ if (value !== void 0) {
82
+ url.searchParams.set(key, value);
83
+ }
84
+ }
85
+ }
86
+ return url.toString();
87
+ }
88
+ async request(url, init) {
65
89
  const maxAttempts = 3;
66
- let attempt = 0;
67
- while (attempt < maxAttempts) {
68
- attempt++;
69
- const res = await this.fetchWithAuth(path, {
70
- method: "POST",
71
- headers: { "content-type": "application/json" },
72
- body: JSON.stringify(body)
73
- });
74
- if (res.status === 429 || res.status >= 500 && res.status <= 599) {
75
- if (attempt < maxAttempts) {
76
- const retryAfter = res.headers.get("retry-after");
77
- let delayMs = 0;
78
- if (retryAfter) {
79
- const seconds = Number(retryAfter);
80
- delayMs = Number.isFinite(seconds) ? seconds * 1e3 : 0;
81
- }
82
- if (delayMs <= 0) {
83
- delayMs = 250 * attempt;
84
- }
85
- await new Promise((r) => setTimeout(r, delayMs));
86
- continue;
90
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
91
+ const headers = new Headers(init.headers);
92
+ headers.set("authorization", `Bearer ${this.config.token}`);
93
+ if (this.config.workspaceId) {
94
+ headers.set("x-workspace-id", this.config.workspaceId);
95
+ }
96
+ try {
97
+ headers.set("user-agent", this.config.userAgent);
98
+ } catch {
99
+ }
100
+ const controller = new AbortController();
101
+ const timeout = setTimeout(() => controller.abort(), this.config.timeout);
102
+ let res;
103
+ try {
104
+ res = await fetch(url, { ...init, headers, signal: controller.signal });
105
+ } finally {
106
+ clearTimeout(timeout);
107
+ }
108
+ if ((res.status === 429 || res.status >= 500 && res.status <= 599) && attempt < maxAttempts) {
109
+ const retryAfter = res.headers.get("retry-after");
110
+ let delayMs = 0;
111
+ if (retryAfter) {
112
+ const seconds = Number(retryAfter);
113
+ delayMs = Number.isFinite(seconds) ? seconds * 1e3 : 0;
87
114
  }
115
+ if (delayMs <= 0) {
116
+ delayMs = 250 * attempt;
117
+ }
118
+ await new Promise((r) => setTimeout(r, delayMs));
119
+ continue;
120
+ }
121
+ const text = await res.text();
122
+ let parsed;
123
+ try {
124
+ parsed = text ? JSON.parse(text) : void 0;
125
+ } catch {
126
+ parsed = text;
88
127
  }
89
- return this.handleResponse(res);
128
+ if (!res.ok) {
129
+ const body = parsed;
130
+ throw new MedalApiError(
131
+ res.status,
132
+ body?.error?.code ?? "UNKNOWN_ERROR",
133
+ body?.error?.message ?? `HTTP ${res.status}: ${res.statusText}`,
134
+ body?.error?.details
135
+ );
136
+ }
137
+ return parsed;
90
138
  }
91
139
  throw new Error("Request failed after retries");
92
140
  }
93
- async fetchWithAuth(path, init) {
94
- const url = `${this.baseUrl}${path}`;
95
- const headers = new Headers(init.headers);
96
- try {
97
- headers.set("user-agent", this.userAgent);
98
- } catch {
99
- }
100
- if (this.auth.kind === "bearer") {
101
- headers.set("authorization", `Bearer ${this.auth.token}`);
102
- } else if (this.auth.kind === "basic") {
103
- headers.set("Client-Id", this.auth.clientId);
104
- headers.set("Client-Secret", this.auth.clientSecret);
105
- }
106
- const controller = new AbortController();
107
- const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
108
- try {
109
- const res = await fetch(url, { ...init, headers, signal: controller.signal });
110
- return res;
111
- } finally {
112
- clearTimeout(timeout);
113
- }
141
+ };
142
+
143
+ // src/resources/contacts.ts
144
+ var Contacts = class {
145
+ constructor(client) {
146
+ this.client = client;
147
+ }
148
+ /** List contacts with cursor-based pagination and optional filters. */
149
+ async list(options) {
150
+ const params = {};
151
+ if (options?.limit !== void 0) params.limit = String(options.limit);
152
+ if (options?.cursor) params.cursor = options.cursor;
153
+ if (options?.status) params.status = options.status;
154
+ if (options?.email_status) params.email_status = options.email_status;
155
+ if (options?.label_ids) params.label_ids = options.label_ids.join(",");
156
+ if (options?.search) params.search = options.search;
157
+ return this.client.get("/api/v1/contacts", params);
158
+ }
159
+ /** Create a new contact. Email must be unique in the workspace. */
160
+ async create(input) {
161
+ return this.client.post("/api/v1/contacts", input);
162
+ }
163
+ /** Get a contact by ID. */
164
+ async get(id) {
165
+ return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}`);
166
+ }
167
+ /** Update one or more fields on a contact. */
168
+ async update(id, input) {
169
+ return this.client.patch(`/api/v1/contacts/${encodeURIComponent(id)}`, input);
170
+ }
171
+ /** Permanently delete a contact. */
172
+ async remove(id) {
173
+ return this.client.delete(`/api/v1/contacts/${encodeURIComponent(id)}`);
174
+ }
175
+ /** Get the activity timeline for a contact. */
176
+ async activities(id, options) {
177
+ const params = {};
178
+ if (options?.limit !== void 0) params.limit = String(options.limit);
179
+ if (options?.cursor) params.cursor = options.cursor;
180
+ return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}/activities`, params);
181
+ }
182
+ /** Add a note to a contact's timeline. */
183
+ async addNote(id, input) {
184
+ return this.client.post(`/api/v1/contacts/${encodeURIComponent(id)}/notes`, input);
185
+ }
186
+ /** Bulk import contacts (max 500). Duplicates are skipped. */
187
+ async import(contacts) {
188
+ return this.client.post("/api/v1/contacts/import", { contacts });
189
+ }
190
+ };
191
+
192
+ // src/resources/deals.ts
193
+ var Deals = class {
194
+ constructor(client) {
195
+ this.client = client;
196
+ }
197
+ /** List deals with cursor-based pagination and optional filters. */
198
+ async list(options) {
199
+ const params = {};
200
+ if (options?.limit !== void 0) params.limit = String(options.limit);
201
+ if (options?.cursor) params.cursor = options.cursor;
202
+ if (options?.status) params.status = options.status;
203
+ if (options?.search) params.search = options.search;
204
+ return this.client.get("/api/v1/deals", params);
205
+ }
206
+ /** Create a new deal. */
207
+ async create(input) {
208
+ return this.client.post("/api/v1/deals", input);
209
+ }
210
+ /** Get a deal by ID. */
211
+ async get(id) {
212
+ return this.client.get(`/api/v1/deals/${encodeURIComponent(id)}`);
114
213
  }
115
- async handleResponse(res) {
116
- const text = await res.text();
117
- let parsed = void 0;
118
- try {
119
- parsed = text ? JSON.parse(text) : void 0;
120
- } catch {
121
- parsed = text;
214
+ /** Update one or more fields on a deal. Set contact_id to null to unlink. */
215
+ async update(id, input) {
216
+ return this.client.patch(`/api/v1/deals/${encodeURIComponent(id)}`, input);
217
+ }
218
+ /** Permanently delete a deal. */
219
+ async remove(id) {
220
+ return this.client.delete(`/api/v1/deals/${encodeURIComponent(id)}`);
221
+ }
222
+ };
223
+
224
+ // src/resources/emails.ts
225
+ var EmailTemplates = class {
226
+ constructor(client) {
227
+ this.client = client;
228
+ }
229
+ /** List all active email templates in the workspace. */
230
+ async list() {
231
+ return this.client.get("/api/v1/emails/templates");
232
+ }
233
+ /** Get a specific email template by slug, optionally with locale resolution. */
234
+ async get(slug, options) {
235
+ const params = {};
236
+ if (options?.locale) params.locale = options.locale;
237
+ if (options?.fallback_locale) params.fallback_locale = options.fallback_locale;
238
+ return this.client.get(`/api/v1/emails/templates/${encodeURIComponent(slug)}`, params);
239
+ }
240
+ };
241
+ var Emails = class {
242
+ constructor(client) {
243
+ this.client = client;
244
+ this.templates = new EmailTemplates(client);
245
+ }
246
+ templates;
247
+ /** Send a transactional email using a template. Returns a queued job ID (HTTP 202). */
248
+ async send(input) {
249
+ return this.client.post("/api/v1/emails", input);
250
+ }
251
+ /** Get the delivery status of a sent email. */
252
+ async get(id) {
253
+ return this.client.get(`/api/v1/emails/${encodeURIComponent(id)}`);
254
+ }
255
+ /** Send the same template to multiple recipients (max 100). Returns HTTP 202. */
256
+ async batch(input) {
257
+ return this.client.post("/api/v1/emails/batch", input);
258
+ }
259
+ };
260
+
261
+ // src/resources/gdpr.ts
262
+ var Gdpr = class {
263
+ constructor(client) {
264
+ this.client = client;
265
+ }
266
+ /** Request a workspace data export. Runs asynchronously. */
267
+ async requestExport() {
268
+ return this.client.post("/api/v1/gdpr/export");
269
+ }
270
+ /** List all workspace export requests. */
271
+ async listExports() {
272
+ return this.client.get("/api/v1/gdpr/exports");
273
+ }
274
+ /** Get the status of a specific export. */
275
+ async getExport(id) {
276
+ return this.client.get(`/api/v1/gdpr/exports/${encodeURIComponent(id)}`);
277
+ }
278
+ /** Record a GDPR consent decision for a contact by email. */
279
+ async recordConsent(input) {
280
+ return this.client.post("/api/v1/gdpr/consent", input);
281
+ }
282
+ /** Get all consent records for a contact by email. */
283
+ async getConsent(email) {
284
+ return this.client.get(`/api/v1/gdpr/consent/${encodeURIComponent(email)}`);
285
+ }
286
+ /** Record cookie consent from an external site (legacy endpoint). */
287
+ async cookieConsent(input) {
288
+ return this.client.post("/api/cookie-consent", input);
289
+ }
290
+ };
291
+
292
+ // src/resources/posts.ts
293
+ var Posts = class {
294
+ constructor(client) {
295
+ this.client = client;
296
+ }
297
+ /** List posts with cursor-based pagination and optional filters. */
298
+ async list(options) {
299
+ const params = {};
300
+ if (options?.limit !== void 0) params.limit = String(options.limit);
301
+ if (options?.cursor) params.cursor = options.cursor;
302
+ if (options?.status) params.status = options.status;
303
+ if (options?.type) params.type = options.type;
304
+ return this.client.get("/api/v1/posts", params);
305
+ }
306
+ /** Create a new post with content and target channels. */
307
+ async create(input) {
308
+ return this.client.post("/api/v1/posts", input);
309
+ }
310
+ /** Get a post by ID, including its per-channel variants. */
311
+ async get(id) {
312
+ return this.client.get(`/api/v1/posts/${encodeURIComponent(id)}`);
313
+ }
314
+ /** Update a draft post's title or content. */
315
+ async update(id, input) {
316
+ return this.client.patch(`/api/v1/posts/${encodeURIComponent(id)}`, input);
317
+ }
318
+ /** Delete a post. */
319
+ async remove(id) {
320
+ return this.client.delete(`/api/v1/posts/${encodeURIComponent(id)}`);
321
+ }
322
+ /** Schedule a post for future publication. */
323
+ async schedule(id, input) {
324
+ return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/schedule`, input);
325
+ }
326
+ /** Publish a post immediately to all target channels. */
327
+ async publish(id) {
328
+ return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/publish`);
329
+ }
330
+ /** List connected publishing channels for this workspace. */
331
+ async channels() {
332
+ return this.client.get("/api/v1/posts/channels");
333
+ }
334
+ };
335
+
336
+ // src/resources/workspaces.ts
337
+ var Workspaces = class {
338
+ constructor(client) {
339
+ this.client = client;
340
+ }
341
+ /** List workspaces accessible to the current API key or OAuth token. */
342
+ async list() {
343
+ return this.client.get("/api/v1/me/workspaces");
344
+ }
345
+ };
346
+
347
+ // src/index.ts
348
+ var Medal = class {
349
+ emails;
350
+ contacts;
351
+ deals;
352
+ gdpr;
353
+ posts;
354
+ workspaces;
355
+ constructor(token, options) {
356
+ if (!token) {
357
+ throw new Error(
358
+ "Authentication token is required. Pass your medal_xxx API key or OAuth access token as the first argument."
359
+ );
122
360
  }
123
- const headers = {};
124
- res.headers.forEach((v, k) => {
125
- headers[k] = v;
361
+ const client = new BaseClient({
362
+ baseUrl: (options?.baseUrl ?? "https://io.medalsocial.com").replace(/\/$/, ""),
363
+ token,
364
+ workspaceId: options?.workspaceId,
365
+ timeout: options?.timeout ?? 3e4,
366
+ userAgent: "medalsocial-sdk/1.0.0 (+https://github.com/Medal-Social/MedalSocial)"
126
367
  });
127
- if (!res.ok) {
128
- const error = new Error(`HTTP ${res.status}: ${res.statusText}`);
129
- error.status = res.status;
130
- error.details = parsed;
131
- throw error;
132
- }
133
- return { status: res.status, data: parsed, headers };
368
+ this.emails = new Emails(client);
369
+ this.contacts = new Contacts(client);
370
+ this.deals = new Deals(client);
371
+ this.gdpr = new Gdpr(client);
372
+ this.posts = new Posts(client);
373
+ this.workspaces = new Workspaces(client);
134
374
  }
135
375
  };
136
- var index_default = MedalSocialClient;
376
+ var index_default = Medal;
137
377
  // Annotate the CommonJS export names for ESM import in node:
138
378
  0 && (module.exports = {
139
- MedalSocialClient
379
+ BaseClient,
380
+ Contacts,
381
+ Deals,
382
+ Emails,
383
+ Gdpr,
384
+ Medal,
385
+ MedalApiError,
386
+ Posts,
387
+ Workspaces
140
388
  });
141
389
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type AuthOptions =\n | { kind: \"basic\"; clientId: string; clientSecret: string }\n | { kind: \"bearer\"; token: string };\n\nexport interface ClientOptions {\n baseUrl?: string;\n auth: AuthOptions;\n timeoutMs?: number;\n userAgent?: string;\n}\n\nexport interface LeadItem {\n name: string;\n email: string;\n company?: string;\n source?: string;\n [key: string]: unknown;\n}\n\nexport interface ContactNoteInput {\n contactId: string;\n note: string;\n [key: string]: unknown;\n}\n\nexport interface NoteInput {\n name: string;\n email: string;\n firstName?: string;\n lastName?: string;\n company?: string;\n phone?: string;\n content?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CookieRecord {\n cookie: string;\n duration: string;\n description: string;\n}\n\nexport interface CookieCategoryConsent {\n allowed: boolean;\n cookieRecords?: CookieRecord[];\n}\n\nexport interface CookieConsentInput {\n domain: string;\n consentStatus: \"granted\" | \"denied\" | \"partial\" | string;\n consentTimestamp: string; // ISO-8601\n ipAddress?: string;\n userAgent?: string;\n cookiePreferences: {\n necessary?: CookieCategoryConsent;\n analytics?: CookieCategoryConsent;\n marketing?: CookieCategoryConsent;\n functional?: CookieCategoryConsent;\n [key: string]: CookieCategoryConsent | undefined;\n };\n}\n\nexport interface EventSignupInput {\n contact: {\n name: string;\n email: string;\n company?: string;\n };\n event: {\n externalId: string;\n name: string;\n description?: string;\n time: string; // ISO-8601\n location?: string;\n thumbnail?: string;\n };\n}\n\nexport interface ApiResponse<T> {\n status: number;\n data: T;\n headers: Record<string, string>;\n}\n\nexport interface TransactionalEmailInput {\n to: string;\n slug: string;\n additionalData?: Record<string, unknown>;\n}\n\nexport class MedalSocialClient {\n private readonly baseUrl: string;\n private readonly auth: AuthOptions;\n private readonly timeoutMs: number;\n private readonly userAgent: string;\n\n constructor(options: ClientOptions) {\n this.baseUrl = (options.baseUrl ?? \"https://api.medalsocial.com\").replace(/\\/$/, \"\");\n this.auth = options.auth;\n this.timeoutMs = options.timeoutMs ?? 30000;\n this.userAgent =\n options.userAgent ??\n \"medal-social-sdk/0.1.0 (+https://github.com/Medal-Social/MedalSocial.git)\";\n }\n\n // Public endpoints\n /** Create one or more leads */\n async createLead<T = unknown>(items: LeadItem[]): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/leads\", items);\n }\n\n /** Create a note attached to a contact by id */\n async createContactNote<T = unknown>(input: ContactNoteInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/contacts/notes\", input);\n }\n\n /** Record a user’s cookie consent preferences */\n async createCookieConsent<T = unknown>(input: CookieConsentInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/cookie-consent\", input);\n }\n\n /** Create an event signup with contact and event details */\n async createEventSignup<T = unknown>(input: EventSignupInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/event-signup\", input);\n }\n\n /** Create a free-form note for inbound messages */\n async createNote<T = unknown>(input: NoteInput): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/notes\", input);\n }\n\n /** Send a transactional email by template slug */\n async sendTransactionalEmail<T = unknown>(\n input: TransactionalEmailInput,\n ): Promise<ApiResponse<T>> {\n return this.post<T>(\"/v1/send-transactional-email\", input);\n }\n\n // Internal HTTP helpers\n private async post<T>(path: string, body: unknown): Promise<ApiResponse<T>> {\n const maxAttempts = 3;\n let attempt = 0;\n\n while (attempt < maxAttempts) {\n attempt++;\n const res = await this.fetchWithAuth(path, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n // Retry on 429/5xx with basic backoff and Retry-After support\n if (res.status === 429 || (res.status >= 500 && res.status <= 599)) {\n if (attempt < maxAttempts) {\n const retryAfter = res.headers.get(\"retry-after\");\n let delayMs = 0;\n if (retryAfter) {\n const seconds = Number(retryAfter);\n delayMs = Number.isFinite(seconds) ? seconds * 1000 : 0;\n }\n if (delayMs <= 0) {\n delayMs = 250 * attempt; // linear backoff\n }\n await new Promise((r) => setTimeout(r, delayMs));\n continue;\n }\n }\n\n return this.handleResponse<T>(res);\n }\n\n throw new Error(\"Request failed after retries\");\n }\n\n private async fetchWithAuth(path: string, init: RequestInit): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const headers = new Headers(init.headers);\n try {\n headers.set(\"user-agent\", this.userAgent);\n } catch {\n // Some environments (e.g., browsers) disallow setting user-agent; ignore.\n }\n\n if (this.auth.kind === \"bearer\") {\n headers.set(\"authorization\", `Bearer ${this.auth.token}`);\n } else if (this.auth.kind === \"basic\") {\n // Medal Social API expects explicit headers for client credentials\n headers.set(\"Client-Id\", this.auth.clientId);\n headers.set(\"Client-Secret\", this.auth.clientSecret);\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const res = await fetch(url, { ...init, headers, signal: controller.signal });\n return res;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async handleResponse<T>(res: Response): Promise<ApiResponse<T>> {\n const text = await res.text();\n let parsed: unknown = undefined;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text as unknown;\n }\n\n const headers: Record<string, string> = {};\n res.headers.forEach((v, k) => {\n headers[k] = v;\n });\n\n if (!res.ok) {\n const error = new Error(`HTTP ${res.status}: ${res.statusText}`) as Error & {\n status?: number;\n details?: unknown;\n };\n error.status = res.status;\n error.details = parsed;\n throw error;\n }\n\n return { status: res.status, data: parsed as T, headers };\n }\n}\n\nexport default MedalSocialClient;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types/common.ts","../src/client.ts","../src/resources/contacts.ts","../src/resources/deals.ts","../src/resources/emails.ts","../src/resources/gdpr.ts","../src/resources/posts.ts","../src/resources/workspaces.ts"],"sourcesContent":["import { BaseClient } from \"./client\";\nimport { Contacts } from \"./resources/contacts\";\nimport { Deals } from \"./resources/deals\";\nimport { Emails } from \"./resources/emails\";\nimport { Gdpr } from \"./resources/gdpr\";\nimport { Posts } from \"./resources/posts\";\nimport { Workspaces } from \"./resources/workspaces\";\n\nexport interface MedalOptions {\n /** Override the base URL (defaults to https://api.medalsocial.com). */\n baseUrl?: string;\n /** Request timeout in ms (default 30000). */\n timeout?: number;\n /**\n * Workspace ID — required for OAuth access tokens, ignored for API keys.\n * API keys are scoped to a single workspace, so the workspace is inferred.\n * OAuth tokens can access multiple workspaces, so you must specify which one.\n */\n workspaceId?: string;\n}\n\n/**\n * Medal Social SDK client.\n *\n * Supports both API key and OAuth access token authentication:\n *\n * @example API Key (recommended for server-side)\n * ```ts\n * import { Medal } from '@medalsocial/sdk';\n *\n * // API keys start with medal_ and are scoped to one workspace\n * const medal = new Medal('medal_xxx');\n * ```\n *\n * @example OAuth Access Token\n * ```ts\n * // OAuth tokens require a workspaceId\n * const medal = new Medal('oauth_access_token', {\n * workspaceId: 'workspace_id_here',\n * });\n * ```\n *\n * @example Full usage\n * ```ts\n * const medal = new Medal('medal_xxx');\n *\n * // Posts — create, schedule, publish\n * const { data: post } = await medal.posts.create({\n * content: 'Hello world!',\n * channel_ids: ['ch_1'],\n * });\n * await medal.posts.schedule(post.id, { scheduled_at: '2026-03-15T10:00:00Z' });\n *\n * // Emails — send transactional emails\n * await medal.emails.send({\n * template_slug: 'welcome',\n * to: 'user@example.com',\n * variables: { name: 'John' },\n * });\n *\n * // Contacts, Deals, GDPR, Workspaces\n * const contacts = await medal.contacts.list({ status: 'lead' });\n * const { data: deal } = await medal.deals.create({ title: 'Acme', value: 50000 });\n * await medal.gdpr.recordConsent({ email: 'u@x.com', consent_type: 'marketing_email', granted: true });\n * const { data: workspaces } = await medal.workspaces.list();\n * ```\n */\nexport class Medal {\n readonly emails: Emails;\n readonly contacts: Contacts;\n readonly deals: Deals;\n readonly gdpr: Gdpr;\n readonly posts: Posts;\n readonly workspaces: Workspaces;\n\n constructor(token: string, options?: MedalOptions) {\n if (!token) {\n throw new Error(\n \"Authentication token is required. Pass your medal_xxx API key or OAuth access token as the first argument.\",\n );\n }\n\n const client = new BaseClient({\n baseUrl: (options?.baseUrl ?? \"https://io.medalsocial.com\").replace(/\\/$/, \"\"),\n token,\n workspaceId: options?.workspaceId,\n timeout: options?.timeout ?? 30000,\n userAgent: \"medalsocial-sdk/1.0.0 (+https://github.com/Medal-Social/MedalSocial)\",\n });\n\n this.emails = new Emails(client);\n this.contacts = new Contacts(client);\n this.deals = new Deals(client);\n this.gdpr = new Gdpr(client);\n this.posts = new Posts(client);\n this.workspaces = new Workspaces(client);\n }\n}\n\n// Re-export all types\nexport { MedalApiError } from \"./types/common\";\nexport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"./types/common\";\nexport type {\n SendEmailInput,\n EmailSendResult,\n EmailSend,\n BatchSendInput,\n BatchSendSummary,\n BatchSendResult,\n EmailTemplate,\n EmailTemplateDetail,\n GetTemplateOptions,\n} from \"./types/emails\";\nexport type {\n Contact,\n ContactCreateResult,\n ContactUpdateResult,\n ContactRemoveResult,\n ContactNoteResult,\n ContactStatus,\n EmailStatus,\n CreateContactInput,\n UpdateContactInput,\n ListContactsOptions,\n ImportContactInput,\n ImportContactsResult,\n Activity,\n AddNoteInput,\n} from \"./types/contacts\";\nexport type {\n Deal,\n DealCreateResult,\n DealUpdateResult,\n DealRemoveResult,\n DealStatus,\n CreateDealInput,\n UpdateDealInput,\n ListDealsOptions,\n} from \"./types/deals\";\nexport type {\n GdprExport,\n ConsentType,\n RecordConsentInput,\n ConsentRecord,\n ConsentResult,\n ContactConsents,\n CookieConsentInput,\n CookieCategoryConsent,\n} from \"./types/gdpr\";\nexport type {\n Post,\n PostType,\n PostVariant,\n PostDetail,\n Channel,\n CreatePostInput,\n UpdatePostInput,\n SchedulePostInput,\n ListPostsOptions,\n ScheduleResult,\n PublishResult,\n} from \"./types/posts\";\nexport type { Workspace } from \"./types/workspaces\";\n\n// Resource class re-exports (for advanced usage)\nexport { Emails } from \"./resources/emails\";\nexport { Contacts } from \"./resources/contacts\";\nexport { Deals } from \"./resources/deals\";\nexport { Gdpr } from \"./resources/gdpr\";\nexport { Posts } from \"./resources/posts\";\nexport { Workspaces } from \"./resources/workspaces\";\nexport { BaseClient } from \"./client\";\n\nexport default Medal;\n","/** Successful API response wrapper */\nexport interface ApiResponse<T> {\n data: T;\n}\n\n/** Paginated API response */\nexport interface PaginatedResponse<T> {\n data: T[];\n pagination: {\n has_more: boolean;\n next_cursor: string | null;\n };\n}\n\n/** API error thrown by the client */\nexport class MedalApiError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(status: number, code: string, message: string, details?: unknown) {\n super(message);\n this.name = \"MedalApiError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\n/** Pagination options for list endpoints */\nexport interface PaginationOptions {\n limit?: number;\n cursor?: string;\n}\n","import { MedalApiError } from \"./types/common\";\n\nexport interface ClientConfig {\n baseUrl: string;\n token: string;\n workspaceId?: string;\n timeout: number;\n userAgent: string;\n}\n\n/**\n * Low-level HTTP client used by all resource classes.\n * Handles authentication, retries, timeout, and error parsing.\n */\nexport class BaseClient {\n readonly config: ClientConfig;\n\n constructor(config: ClientConfig) {\n this.config = config;\n }\n\n async get<T>(path: string, params?: Record<string, string | undefined>): Promise<T> {\n const url = this.buildUrl(path, params);\n return this.request<T>(url, { method: \"GET\" });\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n }\n\n async patch<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"PATCH\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>(this.buildUrl(path), { method: \"DELETE\" });\n }\n\n private buildUrl(path: string, params?: Record<string, string | undefined>): string {\n const url = new URL(`${this.config.baseUrl}${path}`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n }\n }\n return url.toString();\n }\n\n private async request<T>(url: string, init: RequestInit): Promise<T> {\n const maxAttempts = 3;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const headers = new Headers(init.headers);\n headers.set(\"authorization\", `Bearer ${this.config.token}`);\n if (this.config.workspaceId) {\n headers.set(\"x-workspace-id\", this.config.workspaceId);\n }\n try {\n headers.set(\"user-agent\", this.config.userAgent);\n } catch {\n // Browsers disallow setting user-agent\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeout);\n\n let res: Response;\n try {\n res = await fetch(url, { ...init, headers, signal: controller.signal });\n } finally {\n clearTimeout(timeout);\n }\n\n // Retry on 429 / 5xx (but not on the final attempt)\n if ((res.status === 429 || (res.status >= 500 && res.status <= 599)) && attempt < maxAttempts) {\n const retryAfter = res.headers.get(\"retry-after\");\n let delayMs = 0;\n if (retryAfter) {\n const seconds = Number(retryAfter);\n delayMs = Number.isFinite(seconds) ? seconds * 1000 : 0;\n }\n if (delayMs <= 0) {\n delayMs = 250 * attempt;\n }\n await new Promise((r) => setTimeout(r, delayMs));\n continue;\n }\n\n // Parse response\n const text = await res.text();\n let parsed: unknown;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text;\n }\n\n if (!res.ok) {\n const body = parsed as { error?: { code?: string; message?: string; details?: unknown } } | undefined;\n throw new MedalApiError(\n res.status,\n body?.error?.code ?? \"UNKNOWN_ERROR\",\n body?.error?.message ?? `HTTP ${res.status}: ${res.statusText}`,\n body?.error?.details,\n );\n }\n\n return parsed as T;\n }\n\n /* v8 ignore next -- unreachable: loop always returns or throws */\n throw new Error(\"Request failed after retries\");\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"../types/common\";\nimport type {\n Activity,\n AddNoteInput,\n Contact,\n ContactCreateResult,\n ContactNoteResult,\n ContactRemoveResult,\n ContactUpdateResult,\n CreateContactInput,\n ImportContactInput,\n ImportContactsResult,\n ListContactsOptions,\n UpdateContactInput,\n} from \"../types/contacts\";\n\nexport class Contacts {\n constructor(private client: BaseClient) {}\n\n /** List contacts with cursor-based pagination and optional filters. */\n async list(options?: ListContactsOptions): Promise<PaginatedResponse<Contact>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.email_status) params.email_status = options.email_status;\n if (options?.label_ids) params.label_ids = options.label_ids.join(\",\");\n if (options?.search) params.search = options.search;\n return this.client.get(\"/api/v1/contacts\", params);\n }\n\n /** Create a new contact. Email must be unique in the workspace. */\n async create(input: CreateContactInput): Promise<ApiResponse<ContactCreateResult>> {\n return this.client.post(\"/api/v1/contacts\", input);\n }\n\n /** Get a contact by ID. */\n async get(id: string): Promise<ApiResponse<Contact>> {\n return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}`);\n }\n\n /** Update one or more fields on a contact. */\n async update(id: string, input: UpdateContactInput): Promise<ApiResponse<ContactUpdateResult>> {\n return this.client.patch(`/api/v1/contacts/${encodeURIComponent(id)}`, input);\n }\n\n /** Permanently delete a contact. */\n async remove(id: string): Promise<ApiResponse<ContactRemoveResult>> {\n return this.client.delete(`/api/v1/contacts/${encodeURIComponent(id)}`);\n }\n\n /** Get the activity timeline for a contact. */\n async activities(id: string, options?: PaginationOptions): Promise<PaginatedResponse<Activity>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}/activities`, params);\n }\n\n /** Add a note to a contact's timeline. */\n async addNote(id: string, input: AddNoteInput): Promise<ApiResponse<ContactNoteResult>> {\n return this.client.post(`/api/v1/contacts/${encodeURIComponent(id)}/notes`, input);\n }\n\n /** Bulk import contacts (max 500). Duplicates are skipped. */\n async import(contacts: ImportContactInput[]): Promise<ApiResponse<ImportContactsResult>> {\n return this.client.post(\"/api/v1/contacts/import\", { contacts });\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse } from \"../types/common\";\nimport type {\n CreateDealInput,\n Deal,\n DealCreateResult,\n DealRemoveResult,\n DealUpdateResult,\n ListDealsOptions,\n UpdateDealInput,\n} from \"../types/deals\";\n\nexport class Deals {\n constructor(private client: BaseClient) {}\n\n /** List deals with cursor-based pagination and optional filters. */\n async list(options?: ListDealsOptions): Promise<PaginatedResponse<Deal>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.search) params.search = options.search;\n return this.client.get(\"/api/v1/deals\", params);\n }\n\n /** Create a new deal. */\n async create(input: CreateDealInput): Promise<ApiResponse<DealCreateResult>> {\n return this.client.post(\"/api/v1/deals\", input);\n }\n\n /** Get a deal by ID. */\n async get(id: string): Promise<ApiResponse<Deal>> {\n return this.client.get(`/api/v1/deals/${encodeURIComponent(id)}`);\n }\n\n /** Update one or more fields on a deal. Set contact_id to null to unlink. */\n async update(id: string, input: UpdateDealInput): Promise<ApiResponse<DealUpdateResult>> {\n return this.client.patch(`/api/v1/deals/${encodeURIComponent(id)}`, input);\n }\n\n /** Permanently delete a deal. */\n async remove(id: string): Promise<ApiResponse<DealRemoveResult>> {\n return this.client.delete(`/api/v1/deals/${encodeURIComponent(id)}`);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n BatchSendInput,\n BatchSendSummary,\n EmailSend,\n EmailSendResult,\n EmailTemplate,\n EmailTemplateDetail,\n GetTemplateOptions,\n SendEmailInput,\n} from \"../types/emails\";\n\nclass EmailTemplates {\n constructor(private client: BaseClient) {}\n\n /** List all active email templates in the workspace. */\n async list(): Promise<ApiResponse<EmailTemplate[]>> {\n return this.client.get(\"/api/v1/emails/templates\");\n }\n\n /** Get a specific email template by slug, optionally with locale resolution. */\n async get(slug: string, options?: GetTemplateOptions): Promise<ApiResponse<EmailTemplateDetail>> {\n const params: Record<string, string | undefined> = {};\n if (options?.locale) params.locale = options.locale;\n if (options?.fallback_locale) params.fallback_locale = options.fallback_locale;\n return this.client.get(`/api/v1/emails/templates/${encodeURIComponent(slug)}`, params);\n }\n}\n\nexport class Emails {\n readonly templates: EmailTemplates;\n\n constructor(private client: BaseClient) {\n this.templates = new EmailTemplates(client);\n }\n\n /** Send a transactional email using a template. Returns a queued job ID (HTTP 202). */\n async send(input: SendEmailInput): Promise<ApiResponse<EmailSendResult>> {\n return this.client.post(\"/api/v1/emails\", input);\n }\n\n /** Get the delivery status of a sent email. */\n async get(id: string): Promise<ApiResponse<EmailSend>> {\n return this.client.get(`/api/v1/emails/${encodeURIComponent(id)}`);\n }\n\n /** Send the same template to multiple recipients (max 100). Returns HTTP 202. */\n async batch(input: BatchSendInput): Promise<ApiResponse<BatchSendSummary>> {\n return this.client.post(\"/api/v1/emails/batch\", input);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n ConsentRecord,\n ConsentResult,\n CookieConsentInput,\n GdprExport,\n RecordConsentInput,\n} from \"../types/gdpr\";\n\nexport class Gdpr {\n constructor(private client: BaseClient) {}\n\n /** Request a workspace data export. Runs asynchronously. */\n async requestExport(): Promise<ApiResponse<{ request_id: string; status: string }>> {\n return this.client.post(\"/api/v1/gdpr/export\");\n }\n\n /** List all workspace export requests. */\n async listExports(): Promise<ApiResponse<GdprExport[]>> {\n return this.client.get(\"/api/v1/gdpr/exports\");\n }\n\n /** Get the status of a specific export. */\n async getExport(id: string): Promise<ApiResponse<GdprExport>> {\n return this.client.get(`/api/v1/gdpr/exports/${encodeURIComponent(id)}`);\n }\n\n /** Record a GDPR consent decision for a contact by email. */\n async recordConsent(input: RecordConsentInput): Promise<ApiResponse<ConsentResult>> {\n return this.client.post(\"/api/v1/gdpr/consent\", input);\n }\n\n /** Get all consent records for a contact by email. */\n async getConsent(email: string): Promise<ApiResponse<ConsentRecord[]>> {\n return this.client.get(`/api/v1/gdpr/consent/${encodeURIComponent(email)}`);\n }\n\n /** Record cookie consent from an external site (legacy endpoint). */\n async cookieConsent(input: CookieConsentInput): Promise<{ success: boolean; logId?: string }> {\n return this.client.post(\"/api/cookie-consent\", input);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse } from \"../types/common\";\nimport type {\n Channel,\n CreatePostInput,\n ListPostsOptions,\n Post,\n PostDetail,\n PublishResult,\n SchedulePostInput,\n ScheduleResult,\n UpdatePostInput,\n} from \"../types/posts\";\n\nexport class Posts {\n constructor(private client: BaseClient) {}\n\n /** List posts with cursor-based pagination and optional filters. */\n async list(options?: ListPostsOptions): Promise<PaginatedResponse<Post>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.type) params.type = options.type;\n return this.client.get(\"/api/v1/posts\", params);\n }\n\n /** Create a new post with content and target channels. */\n async create(input: CreatePostInput): Promise<ApiResponse<{ id: string }>> {\n return this.client.post(\"/api/v1/posts\", input);\n }\n\n /** Get a post by ID, including its per-channel variants. */\n async get(id: string): Promise<ApiResponse<PostDetail>> {\n return this.client.get(`/api/v1/posts/${encodeURIComponent(id)}`);\n }\n\n /** Update a draft post's title or content. */\n async update(id: string, input: UpdatePostInput): Promise<ApiResponse<{ success: boolean }>> {\n return this.client.patch(`/api/v1/posts/${encodeURIComponent(id)}`, input);\n }\n\n /** Delete a post. */\n async remove(id: string): Promise<ApiResponse<{ success: boolean }>> {\n return this.client.delete(`/api/v1/posts/${encodeURIComponent(id)}`);\n }\n\n /** Schedule a post for future publication. */\n async schedule(id: string, input: SchedulePostInput): Promise<ApiResponse<ScheduleResult>> {\n return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/schedule`, input);\n }\n\n /** Publish a post immediately to all target channels. */\n async publish(id: string): Promise<ApiResponse<PublishResult>> {\n return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/publish`);\n }\n\n /** List connected publishing channels for this workspace. */\n async channels(): Promise<ApiResponse<Channel[]>> {\n return this.client.get(\"/api/v1/posts/channels\");\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type { Workspace } from \"../types/workspaces\";\n\nexport class Workspaces {\n constructor(private client: BaseClient) {}\n\n /** List workspaces accessible to the current API key or OAuth token. */\n async list(): Promise<ApiResponse<Workspace[]>> {\n return this.client.get(\"/api/v1/me/workspaces\");\n }\n}\n"],"mappings":"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","names":[]}