Skip to content

Commit d4567b8

Browse files
committed
Add latest Team API support
1 parent 27fa39c commit d4567b8

3 files changed

Lines changed: 120 additions & 12 deletions

File tree

src/api-surface.spec.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { LettermintClient } from './client';
22
import { Lettermint } from './lettermint';
3+
import type * as Types from './types';
34

45
const mockFetch = jest.fn();
56

@@ -48,6 +49,33 @@ describe('public SDK surface', () => {
4849
expect(mockFetch.mock.calls[0][1].headers).not.toHaveProperty('x-lettermint-token');
4950
});
5051

52+
it('lists blocked file types with bearer token auth', async () => {
53+
mockFetch.mockResolvedValueOnce({
54+
ok: true,
55+
json: async () => ({
56+
extensions: ['exe'],
57+
mime_types: ['application/x-msdownload'],
58+
}),
59+
text: async () => '',
60+
} as Response);
61+
const api = Lettermint.api('api-token');
62+
63+
await expect(api.blockedFileTypes()).resolves.toEqual({
64+
extensions: ['exe'],
65+
mime_types: ['application/x-msdownload'],
66+
});
67+
68+
expect(mockFetch).toHaveBeenCalledWith(
69+
'https://api.lettermint.co/v1/blocked-file-types',
70+
expect.objectContaining({
71+
method: 'GET',
72+
headers: expect.objectContaining({
73+
Authorization: 'Bearer api-token',
74+
}),
75+
})
76+
);
77+
});
78+
5179
it('does not let custom headers override SDK auth headers', async () => {
5280
const client = new LettermintClient({ apiToken: 'api-token', authMode: 'api' });
5381

@@ -92,6 +120,7 @@ describe('api endpoint coverage', () => {
92120
'domain.verifySpecificDnsRecord': 'domains.verifyDnsRecord',
93121
'domain.updateProjects': 'domains.updateProjects',
94122
'v1.ping': 'ping',
123+
'v1.blockedFileTypes': 'blockedFileTypes',
95124
'message.index': 'messages.list',
96125
'message.show': 'messages.retrieve',
97126
'message.events': 'messages.events',
@@ -148,3 +177,64 @@ describe('api endpoint coverage', () => {
148177
}
149178
});
150179
});
180+
181+
describe('generated api types', () => {
182+
it('matches current Team API schema additions', () => {
183+
const messageEvent: Types.MessageEventType = 'auto_replied';
184+
const webhookEvent: Types.WebhookEvent = 'message.auto_replied';
185+
const volumeTier: Types.VolumeTier = 300000;
186+
const suppression: Types.StoreSuppressionData = {
187+
reason: 'manual',
188+
scope: 'global',
189+
emails: ['blocked@example.com'],
190+
};
191+
const routeSettings: Types.UpdateRouteSettingsData = {
192+
redact_email_content: true,
193+
disable_plaintext_generation: false,
194+
};
195+
const routeInboundSettings: Types.UpdateRouteInboundSettingsData = {
196+
inbound_domain: 'inbound.example.com',
197+
inbound_spam_threshold: 3,
198+
attachment_delivery: 'url',
199+
};
200+
const routeUpdate: Types.UpdateRouteData = {
201+
settings: routeSettings,
202+
inbound_settings: routeInboundSettings,
203+
};
204+
const projectCreate: Types.StoreProjectData = {
205+
name: 'Production',
206+
short_token: true,
207+
};
208+
const project: Types.ProjectData = {
209+
id: 'project_123',
210+
name: 'Production',
211+
smtp_enabled: true,
212+
redact_email_content: true,
213+
default_route_id: null,
214+
token_generated_at: null,
215+
token_last_used_at: null,
216+
token_last_used_ip: null,
217+
created_at: '2026-06-28T00:00:00Z',
218+
updated_at: '2026-06-28T00:00:00Z',
219+
};
220+
const projectUpdate: Types.UpdateProjectData = {
221+
redact_email_content: false,
222+
};
223+
const blockedFileTypes: Types.BlockedFileTypesResponse = {
224+
extensions: ['exe'],
225+
mime_types: ['application/x-msdownload'],
226+
};
227+
228+
expect({
229+
messageEvent,
230+
webhookEvent,
231+
volumeTier,
232+
suppression,
233+
routeUpdate,
234+
projectCreate,
235+
project,
236+
projectUpdate,
237+
blockedFileTypes,
238+
}).toBeDefined();
239+
});
240+
});

src/lettermint.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { LettermintClient, type LettermintClientConfig } from './client';
2+
import type * as Types from './types';
23
import {
34
DomainsEndpoint,
45
MessagesEndpoint,
@@ -80,6 +81,10 @@ export class ApiClient {
8081
public async ping(): Promise<string> {
8182
return (await this.client.getRaw('/ping')).trim();
8283
}
84+
85+
public async blockedFileTypes(): Promise<Types.BlockedFileTypesResponse> {
86+
return this.client.get('/blocked-file-types');
87+
}
8388
}
8489

8590
export default Lettermint;

src/types.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export interface MessageEventData {
128128
"timestamp": string;
129129
}
130130

131-
export type MessageEventType = "queued" | "processed" | "suppressed" | "delivered" | "soft_bounced" | "hard_bounced" | "spam_complaint" | "failed" | "blocked" | "policy_rejected" | "unsubscribed" | "opened" | "clicked" | "inbound_received" | "inbound_queued" | "inbound_spam_blocked" | "inbound_processed" | "inbound_retry";
131+
export type MessageEventType = "queued" | "processed" | "suppressed" | "delivered" | "auto_replied" | "soft_bounced" | "hard_bounced" | "spam_complaint" | "failed" | "blocked" | "policy_rejected" | "unsubscribed" | "opened" | "clicked" | "inbound_received" | "inbound_queued" | "inbound_spam_blocked" | "inbound_processed" | "inbound_retry";
132132

133133
export interface MessageListData {
134134
"id": string;
@@ -165,6 +165,7 @@ export interface ProjectData {
165165
"id": string;
166166
"name": string;
167167
"smtp_enabled": boolean;
168+
"redact_email_content": boolean;
168169
"default_route_id": string | null;
169170
"token_generated_at": string | null;
170171
"token_last_used_at": string | null;
@@ -313,6 +314,7 @@ export interface StoreProjectData {
313314
"name": string;
314315
"smtp_enabled"?: boolean;
315316
"initial_routes"?: InitialRoutes;
317+
"short_token"?: boolean;
316318
}
317319

318320
export interface StoreRouteData {
@@ -324,7 +326,7 @@ export interface StoreRouteData {
324326
export interface StoreSuppressionData {
325327
"email"?: string | null;
326328
"reason": SuppressionReason;
327-
"scope": "team" | "project" | "route";
329+
"scope": SuppressionScope;
328330
"route_id"?: string | null;
329331
"project_id"?: string | null;
330332
"emails"?: string[] | null;
@@ -405,6 +407,7 @@ export interface UpdateDomainProjectsData {
405407
export interface UpdateProjectData {
406408
"name"?: string | null;
407409
"smtp_enabled"?: boolean | null;
410+
"redact_email_content"?: boolean | null;
408411
"default_route_id"?: string | null;
409412
}
410413

@@ -414,16 +417,22 @@ export interface UpdateProjectMembersData {
414417

415418
export interface UpdateRouteData {
416419
"name"?: string | null;
417-
"settings"?: {
420+
"settings"?: UpdateRouteSettingsData | unknown;
421+
"inbound_settings"?: UpdateRouteInboundSettingsData | unknown;
422+
}
423+
424+
export interface UpdateRouteInboundSettingsData {
425+
"inbound_domain"?: string | null;
426+
"inbound_spam_threshold"?: number | null;
427+
"attachment_delivery"?: AttachmentDelivery | unknown;
428+
}
429+
430+
export interface UpdateRouteSettingsData {
418431
"track_opens"?: boolean | null;
419432
"track_clicks"?: boolean | null;
433+
"disable_plaintext_generation"?: boolean | null;
420434
"disable_hosted_unsubscribe"?: boolean | null;
421-
};
422-
"inbound_settings"?: {
423-
"inbound_domain"?: string | null;
424-
"inbound_spam_threshold"?: number | null;
425-
"attachment_delivery"?: AttachmentDelivery;
426-
};
435+
"redact_email_content"?: boolean | null;
427436
}
428437

429438
export interface UpdateTeamData {
@@ -445,7 +454,7 @@ export interface UserData {
445454
"avatar": string | null;
446455
}
447456

448-
export type VolumeTier = 300 | 10000 | 50000 | 125000 | 500000 | 750000 | 1000000 | 1500000;
457+
export type VolumeTier = 300 | 10000 | 50000 | 125000 | 300000 | 500000 | 750000 | 1000000 | 1500000;
449458

450459
export interface WebhookData {
451460
"id": string;
@@ -491,7 +500,7 @@ export interface WebhookDeliveryListData {
491500

492501
export type WebhookDeliveryStatus = "pending" | "success" | "failed" | "client_error" | "server_error" | "timeout";
493502

494-
export type WebhookEvent = "message.created" | "message.sent" | "message.delivered" | "message.hard_bounced" | "message.soft_bounced" | "message.spam_complaint" | "message.failed" | "message.suppressed" | "message.unsubscribed" | "message.opened" | "message.clicked" | "message.inbound" | "message.policy_rejected" | "webhook.test";
503+
export type WebhookEvent = "message.created" | "message.sent" | "message.delivered" | "message.auto_replied" | "message.hard_bounced" | "message.soft_bounced" | "message.spam_complaint" | "message.failed" | "message.suppressed" | "message.unsubscribed" | "message.opened" | "message.clicked" | "message.inbound" | "message.policy_rejected" | "webhook.test";
495504

496505
export interface WebhookListData {
497506
"id": string;
@@ -543,6 +552,10 @@ export type DomainUpdateProjectsResponse = {
543552
"data": DomainData;
544553
"message": "Domain projects updated successfully.";
545554
};
555+
export type BlockedFileTypesResponse = {
556+
"extensions": string[];
557+
"mime_types": string[];
558+
};
546559
export type MessageIndexResponse = {
547560
"data": MessageListData[];
548561
"path": string | null;
@@ -589,7 +602,7 @@ export type ProjectDestroyResponse = {
589602
export type ProjectRotateTokenResponse = {
590603
"data": ProjectData;
591604
"new_token": string;
592-
"message": "API token rotated successfully. Please update your integrations.";
605+
"message": "Project API token rotated successfully. Please update your integrations.";
593606
};
594607
export type ProjectUpdateMembersRequest = UpdateProjectMembersData;
595608
export type ProjectUpdateMembersResponse = {

0 commit comments

Comments
 (0)