@zahidzorbaz/tudun 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.
Files changed (145) hide show
  1. package/dist/domain/dto/calendar-event.d.ts +29 -0
  2. package/dist/domain/dto/calendar-event.js +2 -0
  3. package/dist/domain/dto/calendar-event.js.map +1 -0
  4. package/dist/domain/dto/contact.d.ts +26 -0
  5. package/dist/domain/dto/contact.js +2 -0
  6. package/dist/domain/dto/contact.js.map +1 -0
  7. package/dist/domain/dto/email.d.ts +36 -0
  8. package/dist/domain/dto/email.js +2 -0
  9. package/dist/domain/dto/email.js.map +1 -0
  10. package/dist/domain/dto/index.d.ts +4 -0
  11. package/dist/domain/dto/index.js +2 -0
  12. package/dist/domain/dto/index.js.map +1 -0
  13. package/dist/domain/dto/task.d.ts +25 -0
  14. package/dist/domain/dto/task.js +2 -0
  15. package/dist/domain/dto/task.js.map +1 -0
  16. package/dist/domain/ports/auth-service.d.ts +9 -0
  17. package/dist/domain/ports/auth-service.js +2 -0
  18. package/dist/domain/ports/auth-service.js.map +1 -0
  19. package/dist/domain/ports/calendar-service.d.ts +13 -0
  20. package/dist/domain/ports/calendar-service.js +2 -0
  21. package/dist/domain/ports/calendar-service.js.map +1 -0
  22. package/dist/domain/ports/contacts-service.d.ts +10 -0
  23. package/dist/domain/ports/contacts-service.js +2 -0
  24. package/dist/domain/ports/contacts-service.js.map +1 -0
  25. package/dist/domain/ports/gmail-service.d.ts +10 -0
  26. package/dist/domain/ports/gmail-service.js +2 -0
  27. package/dist/domain/ports/gmail-service.js.map +1 -0
  28. package/dist/domain/ports/index.d.ts +5 -0
  29. package/dist/domain/ports/index.js +2 -0
  30. package/dist/domain/ports/index.js.map +1 -0
  31. package/dist/domain/ports/tasks-service.d.ts +15 -0
  32. package/dist/domain/ports/tasks-service.js +2 -0
  33. package/dist/domain/ports/tasks-service.js.map +1 -0
  34. package/dist/infrastructure/config/app-config.d.ts +7 -0
  35. package/dist/infrastructure/config/app-config.js +14 -0
  36. package/dist/infrastructure/config/app-config.js.map +1 -0
  37. package/dist/infrastructure/google/auth.service.d.ts +21 -0
  38. package/dist/infrastructure/google/auth.service.js +196 -0
  39. package/dist/infrastructure/google/auth.service.js.map +1 -0
  40. package/dist/infrastructure/google/calendar.service.d.ts +19 -0
  41. package/dist/infrastructure/google/calendar.service.js +137 -0
  42. package/dist/infrastructure/google/calendar.service.js.map +1 -0
  43. package/dist/infrastructure/google/contacts.service.d.ts +17 -0
  44. package/dist/infrastructure/google/contacts.service.js +182 -0
  45. package/dist/infrastructure/google/contacts.service.js.map +1 -0
  46. package/dist/infrastructure/google/gmail.service.d.ts +17 -0
  47. package/dist/infrastructure/google/gmail.service.js +165 -0
  48. package/dist/infrastructure/google/gmail.service.js.map +1 -0
  49. package/dist/infrastructure/google/index.d.ts +5 -0
  50. package/dist/infrastructure/google/index.js +6 -0
  51. package/dist/infrastructure/google/index.js.map +1 -0
  52. package/dist/infrastructure/google/tasks.service.d.ts +20 -0
  53. package/dist/infrastructure/google/tasks.service.js +133 -0
  54. package/dist/infrastructure/google/tasks.service.js.map +1 -0
  55. package/dist/interface/cli/index.d.ts +2 -0
  56. package/dist/interface/cli/index.js +15 -0
  57. package/dist/interface/cli/index.js.map +1 -0
  58. package/dist/interface/mcp/server.d.ts +2 -0
  59. package/dist/interface/mcp/server.js +84 -0
  60. package/dist/interface/mcp/server.js.map +1 -0
  61. package/dist/interface/mcp/tools/authorize-google.d.ts +3 -0
  62. package/dist/interface/mcp/tools/authorize-google.js +20 -0
  63. package/dist/interface/mcp/tools/authorize-google.js.map +1 -0
  64. package/dist/interface/mcp/tools/complete-task.d.ts +3 -0
  65. package/dist/interface/mcp/tools/complete-task.js +19 -0
  66. package/dist/interface/mcp/tools/complete-task.js.map +1 -0
  67. package/dist/interface/mcp/tools/create-contact.d.ts +3 -0
  68. package/dist/interface/mcp/tools/create-contact.js +34 -0
  69. package/dist/interface/mcp/tools/create-contact.js.map +1 -0
  70. package/dist/interface/mcp/tools/create-event.d.ts +3 -0
  71. package/dist/interface/mcp/tools/create-event.js +32 -0
  72. package/dist/interface/mcp/tools/create-event.js.map +1 -0
  73. package/dist/interface/mcp/tools/create-task-list.d.ts +3 -0
  74. package/dist/interface/mcp/tools/create-task-list.js +18 -0
  75. package/dist/interface/mcp/tools/create-task-list.js.map +1 -0
  76. package/dist/interface/mcp/tools/create-task.d.ts +3 -0
  77. package/dist/interface/mcp/tools/create-task.js +27 -0
  78. package/dist/interface/mcp/tools/create-task.js.map +1 -0
  79. package/dist/interface/mcp/tools/delete-contact.d.ts +3 -0
  80. package/dist/interface/mcp/tools/delete-contact.js +20 -0
  81. package/dist/interface/mcp/tools/delete-contact.js.map +1 -0
  82. package/dist/interface/mcp/tools/delete-event.d.ts +3 -0
  83. package/dist/interface/mcp/tools/delete-event.js +20 -0
  84. package/dist/interface/mcp/tools/delete-event.js.map +1 -0
  85. package/dist/interface/mcp/tools/delete-task.d.ts +3 -0
  86. package/dist/interface/mcp/tools/delete-task.js +21 -0
  87. package/dist/interface/mcp/tools/delete-task.js.map +1 -0
  88. package/dist/interface/mcp/tools/get-event.d.ts +3 -0
  89. package/dist/interface/mcp/tools/get-event.js +18 -0
  90. package/dist/interface/mcp/tools/get-event.js.map +1 -0
  91. package/dist/interface/mcp/tools/get-status.d.ts +3 -0
  92. package/dist/interface/mcp/tools/get-status.js +38 -0
  93. package/dist/interface/mcp/tools/get-status.js.map +1 -0
  94. package/dist/interface/mcp/tools/get-task.d.ts +3 -0
  95. package/dist/interface/mcp/tools/get-task.js +19 -0
  96. package/dist/interface/mcp/tools/get-task.js.map +1 -0
  97. package/dist/interface/mcp/tools/list-contacts.d.ts +3 -0
  98. package/dist/interface/mcp/tools/list-contacts.js +18 -0
  99. package/dist/interface/mcp/tools/list-contacts.js.map +1 -0
  100. package/dist/interface/mcp/tools/list-emails.d.ts +3 -0
  101. package/dist/interface/mcp/tools/list-emails.js +24 -0
  102. package/dist/interface/mcp/tools/list-emails.js.map +1 -0
  103. package/dist/interface/mcp/tools/list-events.d.ts +3 -0
  104. package/dist/interface/mcp/tools/list-events.js +26 -0
  105. package/dist/interface/mcp/tools/list-events.js.map +1 -0
  106. package/dist/interface/mcp/tools/list-task-lists.d.ts +3 -0
  107. package/dist/interface/mcp/tools/list-task-lists.js +15 -0
  108. package/dist/interface/mcp/tools/list-task-lists.js.map +1 -0
  109. package/dist/interface/mcp/tools/list-tasks.d.ts +3 -0
  110. package/dist/interface/mcp/tools/list-tasks.js +25 -0
  111. package/dist/interface/mcp/tools/list-tasks.js.map +1 -0
  112. package/dist/interface/mcp/tools/read-email.d.ts +3 -0
  113. package/dist/interface/mcp/tools/read-email.js +18 -0
  114. package/dist/interface/mcp/tools/read-email.js.map +1 -0
  115. package/dist/interface/mcp/tools/search-contacts.d.ts +3 -0
  116. package/dist/interface/mcp/tools/search-contacts.js +18 -0
  117. package/dist/interface/mcp/tools/search-contacts.js.map +1 -0
  118. package/dist/interface/mcp/tools/send-email.d.ts +3 -0
  119. package/dist/interface/mcp/tools/send-email.js +30 -0
  120. package/dist/interface/mcp/tools/send-email.js.map +1 -0
  121. package/dist/interface/mcp/tools/update-contact.d.ts +3 -0
  122. package/dist/interface/mcp/tools/update-contact.js +33 -0
  123. package/dist/interface/mcp/tools/update-contact.js.map +1 -0
  124. package/dist/interface/mcp/tools/update-event.d.ts +3 -0
  125. package/dist/interface/mcp/tools/update-event.js +31 -0
  126. package/dist/interface/mcp/tools/update-event.js.map +1 -0
  127. package/dist/interface/mcp/tools/update-task.d.ts +3 -0
  128. package/dist/interface/mcp/tools/update-task.js +26 -0
  129. package/dist/interface/mcp/tools/update-task.js.map +1 -0
  130. package/dist/interface/mcp/types.d.ts +12 -0
  131. package/dist/interface/mcp/types.js +2 -0
  132. package/dist/interface/mcp/types.js.map +1 -0
  133. package/dist/shared/errors/index.d.ts +26 -0
  134. package/dist/shared/errors/index.js +46 -0
  135. package/dist/shared/errors/index.js.map +1 -0
  136. package/dist/shared/utils/html-page.d.ts +1 -0
  137. package/dist/shared/utils/html-page.js +9 -0
  138. package/dist/shared/utils/html-page.js.map +1 -0
  139. package/dist/shared/utils/index.d.ts +2 -0
  140. package/dist/shared/utils/index.js +3 -0
  141. package/dist/shared/utils/index.js.map +1 -0
  142. package/dist/shared/utils/open-browser.d.ts +1 -0
  143. package/dist/shared/utils/open-browser.js +10 -0
  144. package/dist/shared/utils/open-browser.js.map +1 -0
  145. package/package.json +43 -0
@@ -0,0 +1,137 @@
1
+ import { CalendarError } from '../../shared/errors/index.js';
2
+ const CALENDAR_API = 'https://www.googleapis.com/calendar/v3';
3
+ export class GoogleCalendarService {
4
+ auth;
5
+ defaultTimeZone;
6
+ constructor(auth, defaultTimeZone) {
7
+ this.auth = auth;
8
+ this.defaultTimeZone = defaultTimeZone;
9
+ }
10
+ async createEvent(input) {
11
+ const token = await this.auth.getAccessToken();
12
+ const timeZone = input.timeZone ?? this.defaultTimeZone;
13
+ const body = {
14
+ summary: input.title,
15
+ description: input.description,
16
+ location: input.location,
17
+ start: { dateTime: input.startTime, timeZone },
18
+ end: { dateTime: input.endTime, timeZone },
19
+ attendees: input.attendees?.map((email) => ({ email })),
20
+ reminders: {
21
+ useDefault: false,
22
+ overrides: [
23
+ { method: 'popup', minutes: 30 },
24
+ { method: 'popup', minutes: 10 },
25
+ ],
26
+ },
27
+ };
28
+ const res = await fetch(`${CALENDAR_API}/calendars/primary/events`, {
29
+ method: 'POST',
30
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
31
+ body: JSON.stringify(body),
32
+ });
33
+ if (!res.ok)
34
+ throw new CalendarError(`Failed to create event: ${await res.text()}`);
35
+ const data = (await res.json());
36
+ return this.mapEventResult(data);
37
+ }
38
+ async listEvents(params) {
39
+ const token = await this.auth.getAccessToken();
40
+ const url = new URL(`${CALENDAR_API}/calendars/primary/events`);
41
+ url.searchParams.set('singleEvents', 'true');
42
+ url.searchParams.set('orderBy', 'startTime');
43
+ url.searchParams.set('timeMin', params.timeMin ?? new Date().toISOString());
44
+ if (params.timeMax)
45
+ url.searchParams.set('timeMax', params.timeMax);
46
+ else {
47
+ const weekLater = new Date();
48
+ weekLater.setDate(weekLater.getDate() + 7);
49
+ url.searchParams.set('timeMax', weekLater.toISOString());
50
+ }
51
+ url.searchParams.set('maxResults', String(params.maxResults ?? 20));
52
+ if (params.query)
53
+ url.searchParams.set('q', params.query);
54
+ const res = await fetch(url, {
55
+ headers: { Authorization: `Bearer ${token}` },
56
+ });
57
+ if (!res.ok)
58
+ throw new CalendarError(`Failed to list events: ${await res.text()}`);
59
+ const data = (await res.json());
60
+ return (data.items ?? []).map((item) => ({
61
+ id: item.id,
62
+ title: item.summary ?? '(No title)',
63
+ startTime: (item.start?.dateTime ??
64
+ item.start?.date),
65
+ endTime: (item.end?.dateTime ??
66
+ item.end?.date),
67
+ location: item.location,
68
+ status: item.status ?? 'confirmed',
69
+ htmlLink: item.htmlLink,
70
+ }));
71
+ }
72
+ async getEvent(eventId) {
73
+ const token = await this.auth.getAccessToken();
74
+ const res = await fetch(`${CALENDAR_API}/calendars/primary/events/${eventId}`, {
75
+ headers: { Authorization: `Bearer ${token}` },
76
+ });
77
+ if (!res.ok)
78
+ throw new CalendarError(`Failed to get event: ${await res.text()}`);
79
+ const data = (await res.json());
80
+ return this.mapEventResult(data);
81
+ }
82
+ async updateEvent(eventId, input) {
83
+ const token = await this.auth.getAccessToken();
84
+ const body = {};
85
+ if (input.title !== undefined)
86
+ body.summary = input.title;
87
+ if (input.description !== undefined)
88
+ body.description = input.description;
89
+ if (input.location !== undefined)
90
+ body.location = input.location;
91
+ if (input.startTime !== undefined) {
92
+ body.start = { dateTime: input.startTime, timeZone: input.timeZone ?? this.defaultTimeZone };
93
+ }
94
+ if (input.endTime !== undefined) {
95
+ body.end = { dateTime: input.endTime, timeZone: input.timeZone ?? this.defaultTimeZone };
96
+ }
97
+ if (input.attendees !== undefined) {
98
+ body.attendees = input.attendees.map((email) => ({ email }));
99
+ }
100
+ const res = await fetch(`${CALENDAR_API}/calendars/primary/events/${eventId}`, {
101
+ method: 'PATCH',
102
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
103
+ body: JSON.stringify(body),
104
+ });
105
+ if (!res.ok)
106
+ throw new CalendarError(`Failed to update event: ${await res.text()}`);
107
+ const data = (await res.json());
108
+ return this.mapEventResult(data);
109
+ }
110
+ async deleteEvent(eventId) {
111
+ const token = await this.auth.getAccessToken();
112
+ const res = await fetch(`${CALENDAR_API}/calendars/primary/events/${eventId}`, {
113
+ method: 'DELETE',
114
+ headers: { Authorization: `Bearer ${token}` },
115
+ });
116
+ if (!res.ok && res.status !== 404) {
117
+ throw new CalendarError(`Failed to delete event: ${await res.text()}`);
118
+ }
119
+ }
120
+ mapEventResult(data) {
121
+ const start = data.start;
122
+ const end = data.end;
123
+ const attendees = data.attendees;
124
+ return {
125
+ id: data.id,
126
+ title: data.summary ?? '(No title)',
127
+ description: data.description,
128
+ location: data.location,
129
+ htmlLink: data.htmlLink,
130
+ startTime: (start?.dateTime ?? start?.date),
131
+ endTime: (end?.dateTime ?? end?.date),
132
+ attendees: attendees?.map((a) => a.email),
133
+ status: data.status ?? 'confirmed',
134
+ };
135
+ }
136
+ }
137
+ //# sourceMappingURL=calendar.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.service.js","sourceRoot":"","sources":["../../../src/infrastructure/google/calendar.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { IAuthService } from '../../domain/ports/auth-service.js';
2
+ import type { IContactsService } from '../../domain/ports/contacts-service.js';
3
+ import type { ContactInput, ContactResult, ContactListItem } from '../../domain/dto/contact.js';
4
+ export declare class GoogleContactsService implements IContactsService {
5
+ private readonly auth;
6
+ constructor(auth: IAuthService);
7
+ createContact(input: ContactInput): Promise<ContactResult>;
8
+ listContacts(params?: {
9
+ pageSize?: number;
10
+ }): Promise<ContactListItem[]>;
11
+ searchContacts(query: string): Promise<ContactListItem[]>;
12
+ updateContact(resourceName: string, input: Partial<ContactInput>): Promise<ContactResult>;
13
+ deleteContact(resourceName: string): Promise<void>;
14
+ private findOrCreateGroup;
15
+ private mapContactResult;
16
+ private mapContactListItem;
17
+ }
@@ -0,0 +1,182 @@
1
+ import { ContactsError } from '../../shared/errors/index.js';
2
+ const PEOPLE_API = 'https://people.googleapis.com/v1';
3
+ const PERSON_FIELDS = 'names,emailAddresses,phoneNumbers,organizations,biographies';
4
+ export class GoogleContactsService {
5
+ auth;
6
+ constructor(auth) {
7
+ this.auth = auth;
8
+ }
9
+ async createContact(input) {
10
+ const token = await this.auth.getAccessToken();
11
+ const person = {
12
+ names: [{ givenName: input.firstName, familyName: input.lastName ?? '' }],
13
+ };
14
+ if (input.phone)
15
+ person.phoneNumbers = [{ value: input.phone, type: 'mobile' }];
16
+ if (input.email)
17
+ person.emailAddresses = [{ value: input.email, type: 'work' }];
18
+ if (input.company || input.title) {
19
+ person.organizations = [{ name: input.company ?? '', title: input.title ?? '' }];
20
+ }
21
+ if (input.notes)
22
+ person.biographies = [{ value: input.notes, contentType: 'TEXT_PLAIN' }];
23
+ if (input.groupName) {
24
+ const groupRes = await this.findOrCreateGroup(token, input.groupName);
25
+ if (groupRes) {
26
+ person.memberships = [
27
+ { contactGroupMembership: { contactGroupResourceName: groupRes } },
28
+ ];
29
+ }
30
+ }
31
+ const res = await fetch(`${PEOPLE_API}/people:createContact`, {
32
+ method: 'POST',
33
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
34
+ body: JSON.stringify(person),
35
+ });
36
+ if (!res.ok)
37
+ throw new ContactsError(`Failed to create contact: ${await res.text()}`);
38
+ const data = (await res.json());
39
+ return this.mapContactResult(data, input.groupName);
40
+ }
41
+ async listContacts(params) {
42
+ const token = await this.auth.getAccessToken();
43
+ const url = new URL(`${PEOPLE_API}/people/me/connections`);
44
+ url.searchParams.set('personFields', PERSON_FIELDS);
45
+ url.searchParams.set('pageSize', String(params?.pageSize ?? 50));
46
+ url.searchParams.set('sortOrder', 'FIRST_NAME_ASCENDING');
47
+ const res = await fetch(url, {
48
+ headers: { Authorization: `Bearer ${token}` },
49
+ });
50
+ if (!res.ok)
51
+ throw new ContactsError(`Failed to list contacts: ${await res.text()}`);
52
+ const data = (await res.json());
53
+ return (data.connections ?? []).map((c) => this.mapContactListItem(c));
54
+ }
55
+ async searchContacts(query) {
56
+ const token = await this.auth.getAccessToken();
57
+ // Warmup request
58
+ await fetch(`${PEOPLE_API}/people:searchContacts?query=&readMask=names`, { headers: { Authorization: `Bearer ${token}` } });
59
+ const url = new URL(`${PEOPLE_API}/people:searchContacts`);
60
+ url.searchParams.set('query', query);
61
+ url.searchParams.set('readMask', PERSON_FIELDS);
62
+ url.searchParams.set('pageSize', '30');
63
+ const res = await fetch(url, {
64
+ headers: { Authorization: `Bearer ${token}` },
65
+ });
66
+ if (!res.ok)
67
+ throw new ContactsError(`Failed to search contacts: ${await res.text()}`);
68
+ const data = (await res.json());
69
+ return (data.results ?? []).map((r) => this.mapContactListItem(r.person));
70
+ }
71
+ async updateContact(resourceName, input) {
72
+ const token = await this.auth.getAccessToken();
73
+ // First fetch current contact to get etag
74
+ const getRes = await fetch(`${PEOPLE_API}/${resourceName}?personFields=${PERSON_FIELDS}`, { headers: { Authorization: `Bearer ${token}` } });
75
+ if (!getRes.ok)
76
+ throw new ContactsError(`Failed to get contact: ${await getRes.text()}`);
77
+ const current = (await getRes.json());
78
+ const person = {
79
+ etag: current.etag,
80
+ };
81
+ const updateFields = [];
82
+ if (input.firstName !== undefined || input.lastName !== undefined) {
83
+ person.names = [{
84
+ givenName: input.firstName ?? (current.names?.[0]?.givenName ?? ''),
85
+ familyName: input.lastName ?? (current.names?.[0]?.familyName ?? ''),
86
+ }];
87
+ updateFields.push('names');
88
+ }
89
+ if (input.phone !== undefined) {
90
+ person.phoneNumbers = [{ value: input.phone, type: 'mobile' }];
91
+ updateFields.push('phoneNumbers');
92
+ }
93
+ if (input.email !== undefined) {
94
+ person.emailAddresses = [{ value: input.email, type: 'work' }];
95
+ updateFields.push('emailAddresses');
96
+ }
97
+ if (input.company !== undefined || input.title !== undefined) {
98
+ person.organizations = [{ name: input.company ?? '', title: input.title ?? '' }];
99
+ updateFields.push('organizations');
100
+ }
101
+ if (input.notes !== undefined) {
102
+ person.biographies = [{ value: input.notes, contentType: 'TEXT_PLAIN' }];
103
+ updateFields.push('biographies');
104
+ }
105
+ if (updateFields.length === 0) {
106
+ throw new ContactsError('No fields to update.');
107
+ }
108
+ const url = new URL(`${PEOPLE_API}/${resourceName}:updateContact`);
109
+ url.searchParams.set('updatePersonFields', updateFields.join(','));
110
+ url.searchParams.set('personFields', PERSON_FIELDS);
111
+ const res = await fetch(url, {
112
+ method: 'PATCH',
113
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
114
+ body: JSON.stringify(person),
115
+ });
116
+ if (!res.ok)
117
+ throw new ContactsError(`Failed to update contact: ${await res.text()}`);
118
+ const data = (await res.json());
119
+ return this.mapContactResult(data);
120
+ }
121
+ async deleteContact(resourceName) {
122
+ const token = await this.auth.getAccessToken();
123
+ const res = await fetch(`${PEOPLE_API}/${resourceName}:deleteContact`, {
124
+ method: 'DELETE',
125
+ headers: { Authorization: `Bearer ${token}` },
126
+ });
127
+ if (!res.ok && res.status !== 404) {
128
+ throw new ContactsError(`Failed to delete contact: ${await res.text()}`);
129
+ }
130
+ }
131
+ // ── Private helpers ──────────────────────────────────────────────
132
+ async findOrCreateGroup(token, groupName) {
133
+ const listRes = await fetch(`${PEOPLE_API}/contactGroups`, {
134
+ headers: { Authorization: `Bearer ${token}` },
135
+ });
136
+ if (listRes.ok) {
137
+ const groups = (await listRes.json());
138
+ const existing = groups.contactGroups?.find((g) => g.name === groupName && g.groupType === 'USER_CONTACT_GROUP');
139
+ if (existing)
140
+ return existing.resourceName;
141
+ }
142
+ const createRes = await fetch(`${PEOPLE_API}/contactGroups`, {
143
+ method: 'POST',
144
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
145
+ body: JSON.stringify({ contactGroup: { name: groupName } }),
146
+ });
147
+ if (createRes.ok) {
148
+ const created = (await createRes.json());
149
+ return created.resourceName;
150
+ }
151
+ return undefined;
152
+ }
153
+ mapContactResult(data, groupName) {
154
+ const names = data.names;
155
+ const phones = data.phoneNumbers;
156
+ const emails = data.emailAddresses;
157
+ const orgs = data.organizations;
158
+ return {
159
+ resourceName: data.resourceName,
160
+ name: names?.[0]?.displayName ?? '',
161
+ phone: phones?.[0]?.value,
162
+ email: emails?.[0]?.value,
163
+ company: orgs?.[0]?.name || undefined,
164
+ title: orgs?.[0]?.title || undefined,
165
+ groupName,
166
+ };
167
+ }
168
+ mapContactListItem(data) {
169
+ const names = data.names;
170
+ const phones = data.phoneNumbers;
171
+ const emails = data.emailAddresses;
172
+ const orgs = data.organizations;
173
+ return {
174
+ resourceName: data.resourceName,
175
+ name: names?.[0]?.displayName ?? '(No name)',
176
+ phone: phones?.[0]?.value,
177
+ email: emails?.[0]?.value,
178
+ company: orgs?.[0]?.name || undefined,
179
+ };
180
+ }
181
+ }
182
+ //# sourceMappingURL=contacts.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.service.js","sourceRoot":"","sources":["../../../src/infrastructure/google/contacts.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { IAuthService } from '../../domain/ports/auth-service.js';
2
+ import type { IGmailService } from '../../domain/ports/gmail-service.js';
3
+ import type { EmailInput, EmailResult, EmailListItem, EmailDetail } from '../../domain/dto/email.js';
4
+ export declare class GoogleGmailService implements IGmailService {
5
+ private readonly auth;
6
+ constructor(auth: IAuthService);
7
+ sendEmail(input: EmailInput): Promise<EmailResult>;
8
+ listEmails(params?: {
9
+ query?: string;
10
+ maxResults?: number;
11
+ labelIds?: string[];
12
+ }): Promise<EmailListItem[]>;
13
+ readEmail(messageId: string): Promise<EmailDetail>;
14
+ private fetchMessageMetadata;
15
+ private parseFullMessage;
16
+ private extractBody;
17
+ }
@@ -0,0 +1,165 @@
1
+ import { GmailError } from '../../shared/errors/index.js';
2
+ const GMAIL_API = 'https://gmail.googleapis.com/gmail/v1/users/me';
3
+ export class GoogleGmailService {
4
+ auth;
5
+ constructor(auth) {
6
+ this.auth = auth;
7
+ }
8
+ async sendEmail(input) {
9
+ const token = await this.auth.getAccessToken();
10
+ const lines = [
11
+ `To: ${input.to.join(', ')}`,
12
+ ];
13
+ if (input.cc?.length)
14
+ lines.push(`Cc: ${input.cc.join(', ')}`);
15
+ if (input.bcc?.length)
16
+ lines.push(`Bcc: ${input.bcc.join(', ')}`);
17
+ lines.push(`Subject: =?UTF-8?B?${Buffer.from(input.subject).toString('base64')}?=`);
18
+ if (input.replyToMessageId) {
19
+ lines.push(`In-Reply-To: ${input.replyToMessageId}`);
20
+ lines.push(`References: ${input.replyToMessageId}`);
21
+ }
22
+ lines.push('Content-Type: text/plain; charset="UTF-8"');
23
+ lines.push('');
24
+ lines.push(input.body);
25
+ const raw = Buffer.from(lines.join('\r\n'))
26
+ .toString('base64')
27
+ .replace(/\+/g, '-')
28
+ .replace(/\//g, '_')
29
+ .replace(/=+$/, '');
30
+ const res = await fetch(`${GMAIL_API}/messages/send`, {
31
+ method: 'POST',
32
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
33
+ body: JSON.stringify({ raw }),
34
+ });
35
+ if (!res.ok)
36
+ throw new GmailError(`Failed to send email: ${await res.text()}`);
37
+ const data = (await res.json());
38
+ return {
39
+ id: data.id,
40
+ threadId: data.threadId,
41
+ labelIds: data.labelIds ?? [],
42
+ };
43
+ }
44
+ async listEmails(params) {
45
+ const token = await this.auth.getAccessToken();
46
+ const url = new URL(`${GMAIL_API}/messages`);
47
+ if (params?.query)
48
+ url.searchParams.set('q', params.query);
49
+ url.searchParams.set('maxResults', String(params?.maxResults ?? 20));
50
+ if (params?.labelIds?.length) {
51
+ for (const label of params.labelIds) {
52
+ url.searchParams.append('labelIds', label);
53
+ }
54
+ }
55
+ const res = await fetch(url, {
56
+ headers: { Authorization: `Bearer ${token}` },
57
+ });
58
+ if (!res.ok)
59
+ throw new GmailError(`Failed to list emails: ${await res.text()}`);
60
+ const data = (await res.json());
61
+ if (!data.messages?.length)
62
+ return [];
63
+ // Fetch metadata for each message
64
+ const items = [];
65
+ for (const msg of data.messages) {
66
+ const detail = await this.fetchMessageMetadata(token, msg.id);
67
+ if (detail)
68
+ items.push(detail);
69
+ }
70
+ return items;
71
+ }
72
+ async readEmail(messageId) {
73
+ const token = await this.auth.getAccessToken();
74
+ const res = await fetch(`${GMAIL_API}/messages/${messageId}?format=full`, {
75
+ headers: { Authorization: `Bearer ${token}` },
76
+ });
77
+ if (!res.ok)
78
+ throw new GmailError(`Failed to read email: ${await res.text()}`);
79
+ const data = (await res.json());
80
+ return this.parseFullMessage(data);
81
+ }
82
+ // ── Private helpers ──────────────────────────────────────────────
83
+ async fetchMessageMetadata(token, messageId) {
84
+ const res = await fetch(`${GMAIL_API}/messages/${messageId}?format=metadata&metadataHeaders=From&metadataHeaders=Subject&metadataHeaders=Date`, { headers: { Authorization: `Bearer ${token}` } });
85
+ if (!res.ok)
86
+ return null;
87
+ const data = (await res.json());
88
+ const headers = data.payload?.headers ?? [];
89
+ const labelIds = data.labelIds ?? [];
90
+ return {
91
+ id: data.id,
92
+ threadId: data.threadId,
93
+ snippet: data.snippet ?? '',
94
+ from: headers.find((h) => h.name === 'From')?.value ?? '',
95
+ subject: headers.find((h) => h.name === 'Subject')?.value ?? '(No subject)',
96
+ date: headers.find((h) => h.name === 'Date')?.value ?? '',
97
+ labelIds,
98
+ isUnread: labelIds.includes('UNREAD'),
99
+ };
100
+ }
101
+ parseFullMessage(data) {
102
+ const payload = data.payload;
103
+ const headers = payload?.headers ?? [];
104
+ const labelIds = data.labelIds ?? [];
105
+ const getHeader = (name) => headers.find((h) => h.name.toLowerCase() === name.toLowerCase())?.value ?? '';
106
+ const toHeader = getHeader('To');
107
+ const ccHeader = getHeader('Cc');
108
+ return {
109
+ id: data.id,
110
+ threadId: data.threadId,
111
+ from: getHeader('From'),
112
+ to: toHeader ? toHeader.split(',').map((s) => s.trim()) : [],
113
+ cc: ccHeader ? ccHeader.split(',').map((s) => s.trim()) : undefined,
114
+ subject: getHeader('Subject') || '(No subject)',
115
+ date: getHeader('Date'),
116
+ body: this.extractBody(payload),
117
+ snippet: data.snippet ?? '',
118
+ labelIds,
119
+ isUnread: labelIds.includes('UNREAD'),
120
+ };
121
+ }
122
+ extractBody(payload) {
123
+ // Try to get plain text body
124
+ const body = payload.body;
125
+ if (body?.data) {
126
+ return Buffer.from(body.data, 'base64url').toString('utf-8');
127
+ }
128
+ // Check parts for multipart messages
129
+ const parts = payload.parts;
130
+ if (parts) {
131
+ // Prefer text/plain
132
+ const textPart = parts.find((p) => p.mimeType === 'text/plain');
133
+ if (textPart) {
134
+ const partBody = textPart.body;
135
+ if (partBody?.data) {
136
+ return Buffer.from(partBody.data, 'base64url').toString('utf-8');
137
+ }
138
+ }
139
+ // Fallback to text/html
140
+ const htmlPart = parts.find((p) => p.mimeType === 'text/html');
141
+ if (htmlPart) {
142
+ const partBody = htmlPart.body;
143
+ if (partBody?.data) {
144
+ const html = Buffer.from(partBody.data, 'base64url').toString('utf-8');
145
+ return html.replace(/<[^>]+>/g, '').trim();
146
+ }
147
+ }
148
+ // Check nested parts (multipart/alternative inside multipart/mixed)
149
+ for (const part of parts) {
150
+ const nestedParts = part.parts;
151
+ if (nestedParts) {
152
+ const nestedText = nestedParts.find((p) => p.mimeType === 'text/plain');
153
+ if (nestedText) {
154
+ const partBody = nestedText.body;
155
+ if (partBody?.data) {
156
+ return Buffer.from(partBody.data, 'base64url').toString('utf-8');
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ return '(No readable body)';
163
+ }
164
+ }
165
+ //# sourceMappingURL=gmail.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmail.service.js","sourceRoot":"","sources":["../../../src/infrastructure/google/gmail.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { GoogleAuthService } from './auth.service.js';
2
+ export { GoogleCalendarService } from './calendar.service.js';
3
+ export { GoogleTasksService } from './tasks.service.js';
4
+ export { GoogleContactsService } from './contacts.service.js';
5
+ export { GoogleGmailService } from './gmail.service.js';
@@ -0,0 +1,6 @@
1
+ export { GoogleAuthService } from './auth.service.js';
2
+ export { GoogleCalendarService } from './calendar.service.js';
3
+ export { GoogleTasksService } from './tasks.service.js';
4
+ export { GoogleContactsService } from './contacts.service.js';
5
+ export { GoogleGmailService } from './gmail.service.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infrastructure/google/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { IAuthService } from '../../domain/ports/auth-service.js';
2
+ import type { ITasksService } from '../../domain/ports/tasks-service.js';
3
+ import type { TaskInput, TaskResult, TaskListInput, TaskListResult } from '../../domain/dto/task.js';
4
+ export declare class GoogleTasksService implements ITasksService {
5
+ private readonly auth;
6
+ constructor(auth: IAuthService);
7
+ createTask(taskListId: string, input: TaskInput): Promise<TaskResult>;
8
+ listTasks(taskListId: string, params?: {
9
+ showCompleted?: boolean;
10
+ showHidden?: boolean;
11
+ maxResults?: number;
12
+ }): Promise<TaskResult[]>;
13
+ getTask(taskListId: string, taskId: string): Promise<TaskResult>;
14
+ updateTask(taskListId: string, taskId: string, input: Partial<TaskInput>): Promise<TaskResult>;
15
+ deleteTask(taskListId: string, taskId: string): Promise<void>;
16
+ completeTask(taskListId: string, taskId: string): Promise<TaskResult>;
17
+ listTaskLists(): Promise<TaskListResult[]>;
18
+ createTaskList(input: TaskListInput): Promise<TaskListResult>;
19
+ private mapTask;
20
+ }