@zapier/google-contacts-connector 0.0.0 → 0.1.1

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 ADDED
@@ -0,0 +1,1134 @@
1
+ // index.ts
2
+ import { defineConnector, toFunctions } from "@zapier/connectors-sdk";
3
+
4
+ // connections.ts
5
+ import {
6
+ defineEnvTokenResolver,
7
+ zapierConnectionResolver
8
+ } from "@zapier/connectors-sdk";
9
+ var connectionResolvers = {
10
+ "google-contacts": [zapierConnectionResolver, defineEnvTokenResolver()]
11
+ };
12
+
13
+ // scripts/copyOtherContact.ts
14
+ import { defineTool, handleIfScriptMain } from "@zapier/connectors-sdk";
15
+ import { z as z2 } from "zod";
16
+
17
+ // lib/google-contacts.ts
18
+ import { ConnectorHttpError } from "@zapier/connectors-sdk";
19
+ import { z } from "zod";
20
+ var DEFAULT_PERSON_FIELDS = "names,emailAddresses,phoneNumbers,addresses,organizations,biographies,birthdays,urls,events,relations,memberships,nicknames,occupations,photos,metadata,userDefined";
21
+ var DEFAULT_GROUP_FIELDS = "name,groupType,memberCount,clientData,metadata";
22
+ var UPDATABLE_PERSON_FIELDS = [
23
+ "names",
24
+ "emailAddresses",
25
+ "phoneNumbers",
26
+ "addresses",
27
+ "organizations",
28
+ "biographies",
29
+ "birthdays",
30
+ "urls",
31
+ "events",
32
+ "relations",
33
+ "userDefined"
34
+ ];
35
+ function deriveUpdatePersonFields(input) {
36
+ return UPDATABLE_PERSON_FIELDS.filter((f) => input[f] !== void 0).join(
37
+ ","
38
+ );
39
+ }
40
+ var nameFields = {
41
+ givenName: z.string().describe("First name.").optional(),
42
+ familyName: z.string().describe("Last name.").optional(),
43
+ middleName: z.string().describe("Middle name.").optional(),
44
+ honorificPrefix: z.string().describe("Title prefix, e.g. Dr., Ms.").optional(),
45
+ honorificSuffix: z.string().describe("Suffix, e.g. Jr., PhD.").optional(),
46
+ unstructuredName: z.string().describe(
47
+ "The full formatted name. Drives the display name \u2014 set it when changing name parts or the display name goes stale."
48
+ ).optional()
49
+ };
50
+ var NameSchema = z.object({
51
+ ...nameFields,
52
+ // Read-only computed names the API returns (output only — kept off NameInput).
53
+ displayName: z.string().describe("Read-only. The API's computed display name for the contact.").optional(),
54
+ displayNameLastFirst: z.string().describe("Read-only. The computed display name in last-name-first order.").optional()
55
+ });
56
+ var NameInput = z.strictObject(nameFields);
57
+ var emailFields = {
58
+ value: z.string().describe("The email address."),
59
+ type: z.string().describe("Free-text label, e.g. home, work, other, or a custom label.").optional()
60
+ };
61
+ var EmailAddressSchema = z.object(emailFields);
62
+ var EmailAddressInput = z.strictObject(emailFields);
63
+ var phoneFields = {
64
+ value: z.string().describe("The phone number, in any format the user has it."),
65
+ type: z.string().describe("Free-text label, e.g. mobile, home, work, or a custom label.").optional()
66
+ };
67
+ var PhoneNumberSchema = z.object(phoneFields);
68
+ var PhoneNumberInput = z.strictObject(phoneFields);
69
+ var addressFields = {
70
+ streetAddress: z.string().describe("Street and number.").optional(),
71
+ extendedAddress: z.string().describe("Apartment, suite, unit, etc.").optional(),
72
+ city: z.string().describe("City / locality.").optional(),
73
+ region: z.string().describe("State / province / region.").optional(),
74
+ postalCode: z.string().describe("Postal or ZIP code.").optional(),
75
+ country: z.string().describe("Country name.").optional(),
76
+ countryCode: z.string().describe("ISO 3166-1 alpha-2 country code, e.g. US.").optional(),
77
+ poBox: z.string().describe("PO box.").optional(),
78
+ type: z.string().describe("Free-text label, e.g. home, work.").optional()
79
+ };
80
+ var AddressSchema = z.object(addressFields);
81
+ var AddressInput = z.strictObject(addressFields);
82
+ var organizationFields = {
83
+ name: z.string().describe("Company / organization name.").optional(),
84
+ title: z.string().describe("Job title.").optional(),
85
+ department: z.string().describe("Department.").optional(),
86
+ type: z.string().describe("Free-text label, e.g. work, school.").optional()
87
+ };
88
+ var OrganizationSchema = z.object(organizationFields);
89
+ var OrganizationInput = z.strictObject(organizationFields);
90
+ var biographyFields = {
91
+ value: z.string().describe("The note text."),
92
+ contentType: z.enum(["TEXT_PLAIN", "TEXT_HTML"]).describe("Whether the value is plain text or HTML.").optional()
93
+ };
94
+ var BiographySchema = z.object(biographyFields);
95
+ var BiographyInput = z.strictObject(biographyFields);
96
+ var dateFields = {
97
+ year: z.number().int().describe("Four-digit year. Omit if unknown.").optional(),
98
+ month: z.number().int().describe("Month, 1-12.").optional(),
99
+ day: z.number().int().describe("Day of month, 1-31.").optional()
100
+ };
101
+ var dateDescription = "A calendar date. Omit year for year-less dates (e.g. a birthday with no year).";
102
+ var DateSchema = z.object(dateFields).describe(dateDescription);
103
+ var DateInput = z.strictObject(dateFields).describe(dateDescription);
104
+ var birthdayFields = {
105
+ date: DateSchema.optional(),
106
+ text: z.string().describe("Free-text birthday when a structured date is not available.").optional()
107
+ };
108
+ var BirthdaySchema = z.object(birthdayFields);
109
+ var BirthdayInput = z.strictObject({
110
+ date: DateInput.optional(),
111
+ text: birthdayFields.text
112
+ });
113
+ var calendarEventFields = {
114
+ date: DateSchema.optional(),
115
+ type: z.string().describe("Free-text label, e.g. anniversary, or a custom label.").optional()
116
+ };
117
+ var ContactEventSchema = z.object(calendarEventFields);
118
+ var ContactEventInput = z.strictObject({
119
+ date: DateInput.optional(),
120
+ type: calendarEventFields.type
121
+ });
122
+ var relationFields = {
123
+ person: z.string().describe("The related person's name, free text, e.g. Jane Doe."),
124
+ type: z.string().describe("Relationship label, e.g. spouse, child, manager.").optional()
125
+ };
126
+ var RelationSchema = z.object(relationFields);
127
+ var RelationInput = z.strictObject(relationFields);
128
+ var userDefinedFields = {
129
+ key: z.string().describe("The custom field's name."),
130
+ value: z.string().describe("The custom field's value.")
131
+ };
132
+ var UserDefinedSchema = z.object(userDefinedFields);
133
+ var UserDefinedInput = z.strictObject(userDefinedFields);
134
+ var urlFields = {
135
+ value: z.string().describe("The value, e.g. a URL."),
136
+ type: z.string().describe("Free-text label.").optional()
137
+ };
138
+ var UrlSchema = z.object(urlFields);
139
+ var UrlInput = z.strictObject(urlFields);
140
+ var MembershipInput = z.strictObject({
141
+ contactGroupResourceName: z.string().describe(
142
+ "A contact group resource name (contactGroups/\u2026) from listContactGroups."
143
+ )
144
+ });
145
+ var PhotoSchema = z.object({
146
+ url: z.string().optional(),
147
+ default: z.boolean().optional()
148
+ });
149
+ var MembershipSchema = z.object({
150
+ contactGroupMembership: z.object({ contactGroupResourceName: z.string().optional() }).optional()
151
+ });
152
+ var PersonSchema = z.object({
153
+ resourceName: z.string().describe(
154
+ "Canonical contact id, e.g. people/c12345. Pass to getContact/updateContact/deleteContact/modifyContactGroupMembers."
155
+ ),
156
+ etag: z.string().describe(
157
+ "Optimistic-concurrency token. Used internally by updateContact; changes after every edit."
158
+ ).optional(),
159
+ names: z.array(NameSchema).optional(),
160
+ emailAddresses: z.array(EmailAddressSchema).optional(),
161
+ phoneNumbers: z.array(PhoneNumberSchema).optional(),
162
+ addresses: z.array(AddressSchema).optional(),
163
+ organizations: z.array(OrganizationSchema).optional(),
164
+ biographies: z.array(BiographySchema).optional(),
165
+ birthdays: z.array(BirthdaySchema).optional(),
166
+ urls: z.array(UrlSchema).optional(),
167
+ events: z.array(ContactEventSchema).optional(),
168
+ relations: z.array(RelationSchema).optional(),
169
+ userDefined: z.array(UserDefinedSchema).optional(),
170
+ nicknames: z.array(z.object({ value: z.string().optional() })).optional(),
171
+ occupations: z.array(z.object({ value: z.string().optional() })).optional(),
172
+ memberships: z.array(MembershipSchema).optional(),
173
+ photos: z.array(PhotoSchema).optional()
174
+ }).describe(
175
+ "A contact. Canonical People API Person resource \u2014 no flattening or derived fields."
176
+ );
177
+ var PersonResponseSchema = z.object({
178
+ person: PersonSchema.optional()
179
+ });
180
+ var ContactGroupSchema = z.object({
181
+ resourceName: z.string().describe(
182
+ "Canonical group id, e.g. contactGroups/1a2b3c. Pass to modifyContactGroupMembers."
183
+ ),
184
+ etag: z.string().describe(
185
+ "Optimistic-concurrency token. Used internally by updateContactGroup."
186
+ ).optional(),
187
+ name: z.string().describe("The group (label) name.").optional(),
188
+ formattedName: z.string().describe("Display name (localized for system groups).").optional(),
189
+ groupType: z.enum(["USER_CONTACT_GROUP", "SYSTEM_CONTACT_GROUP"]).describe(
190
+ "USER_CONTACT_GROUP (editable) or SYSTEM_CONTACT_GROUP (e.g. myContacts, starred \u2014 not renamable/deletable)."
191
+ ).optional(),
192
+ memberCount: z.number().int().describe("Number of contacts in the group.").optional(),
193
+ memberResourceNames: z.array(z.string()).describe(
194
+ "Member contact resource names (when requested via maxMembers)."
195
+ ).optional()
196
+ }).describe("A contact group (label).");
197
+ var RATE_LIMIT_STATUSES = /* @__PURE__ */ new Set(["RESOURCE_EXHAUSTED"]);
198
+ async function readBody(res) {
199
+ let text;
200
+ try {
201
+ text = await res.text();
202
+ } catch {
203
+ return void 0;
204
+ }
205
+ if (text === "") return "";
206
+ try {
207
+ return JSON.parse(text);
208
+ } catch {
209
+ return text;
210
+ }
211
+ }
212
+ async function throwForGoogleContacts(res, toolName) {
213
+ if (res.ok) return res;
214
+ const body = await readBody(res);
215
+ const err = body?.error;
216
+ const status = err?.status;
217
+ const apiMessage = err?.message;
218
+ const prefix = `Google Contacts ${toolName} ${res.status}`;
219
+ let message;
220
+ if (res.status === 401 || status === "UNAUTHENTICATED") {
221
+ message = `${prefix}: invalid or expired credentials. Reconnect Google Contacts.`;
222
+ } else if (res.status === 429 || status && RATE_LIMIT_STATUSES.has(status)) {
223
+ message = `${prefix}: RESOURCE_EXHAUSTED \u2014 rate/quota limited (the per-day Contact Writes quota is the common cause for writes). Back off and retry with jitter (the API does not document a Retry-After header).`;
224
+ } else if (res.status === 403) {
225
+ message = `${prefix}: ${status ?? "PERMISSION_DENIED"} \u2014 the granted OAuth scope is too narrow. Reconnect Google Contacts with contacts access (and contacts.other.readonly for other-contacts tools).`;
226
+ } else if (res.status === 400 && status === "FAILED_PRECONDITION") {
227
+ message = `${prefix}: FAILED_PRECONDITION \u2014 the contact changed since it was read (stale etag). Re-fetch with getContact and retry.`;
228
+ } else if (res.status === 400) {
229
+ message = `${prefix}: ${status ?? "INVALID_ARGUMENT"} \u2014 ${apiMessage ?? "invalid request"}. Check the field mask and that no optional section was sent empty ([] or [{}]).`;
230
+ } else if (res.status === 404 || status === "NOT_FOUND") {
231
+ message = `${prefix}: NOT_FOUND \u2014 ${apiMessage ?? "the contact or group does not exist"}. Verify the resourceName (resolve contacts via listContacts/searchContacts, groups via listContactGroups).`;
232
+ } else if (res.status === 409 || status === "ALREADY_EXISTS") {
233
+ message = `${prefix}: ALREADY_EXISTS \u2014 ${apiMessage ?? "a resource with that name already exists"}.`;
234
+ } else {
235
+ message = `${prefix}: ${apiMessage ?? status ?? "request failed"}`;
236
+ }
237
+ throw ConnectorHttpError.fromResponseBody(res, body, { message });
238
+ }
239
+
240
+ // scripts/copyOtherContact.ts
241
+ var inputSchema = z2.object({
242
+ resourceName: z2.string().describe(
243
+ "Other-contact resource name, e.g. otherContacts/c12345 (from listOtherContacts or searchOtherContacts)."
244
+ ),
245
+ copyMask: z2.string().describe(
246
+ "Which fields to copy onto the new contact. Only emailAddresses, names, and phoneNumbers are supported. Defaults to all three."
247
+ ).default("names,emailAddresses,phoneNumbers")
248
+ }).strict();
249
+ var definition = defineTool({
250
+ name: "copyOtherContact",
251
+ title: "Copy Other Contact",
252
+ description: `Promote an "other contact" into the user's saved contacts (myContacts), returning an editable contact with a people/c\u2026 resourceName.`,
253
+ inputSchema,
254
+ outputSchema: PersonSchema,
255
+ annotations: {
256
+ readOnlyHint: false,
257
+ destructiveHint: false,
258
+ idempotentHint: false,
259
+ openWorldHint: true
260
+ },
261
+ connection: "google-contacts",
262
+ run: async (input, ctx) => {
263
+ const url = `https://people.googleapis.com/v1/${input.resourceName}:copyOtherContactToMyContactsGroup`;
264
+ const res = await ctx.fetch(url, {
265
+ method: "POST",
266
+ headers: { "Content-Type": "application/json" },
267
+ body: JSON.stringify({ copyMask: input.copyMask })
268
+ });
269
+ await throwForGoogleContacts(res, "copyOtherContact");
270
+ return res.json();
271
+ }
272
+ });
273
+ var copyOtherContact_default = definition;
274
+ await handleIfScriptMain(import.meta, definition, { connectionResolvers });
275
+
276
+ // scripts/createContact.ts
277
+ import { defineTool as defineTool2, handleIfScriptMain as handleIfScriptMain2 } from "@zapier/connectors-sdk";
278
+ import { z as z3 } from "zod";
279
+ var inputSchema2 = z3.object({
280
+ names: z3.array(NameInput).describe(
281
+ "Name parts. Set unstructuredName (the full formatted name) or it is derived from the parts."
282
+ ).optional(),
283
+ emailAddresses: z3.array(EmailAddressInput).describe("Email addresses.").optional(),
284
+ phoneNumbers: z3.array(PhoneNumberInput).describe("Phone numbers.").optional(),
285
+ addresses: z3.array(AddressInput).describe("Postal addresses.").optional(),
286
+ organizations: z3.array(OrganizationInput).describe("Companies / job titles.").optional(),
287
+ biographies: z3.array(BiographyInput).describe("Notes about the contact.").optional(),
288
+ birthdays: z3.array(BirthdayInput).describe(
289
+ "Birthdays. Use a structured date (year optional for year-less birthdays)."
290
+ ).optional(),
291
+ urls: z3.array(UrlInput).describe("Websites or profile links.").optional(),
292
+ events: z3.array(ContactEventInput).describe("Custom dates such as anniversaries.").optional(),
293
+ relations: z3.array(RelationInput).describe("Related people (e.g. spouse, manager).").optional(),
294
+ userDefined: z3.array(UserDefinedInput).describe("Custom key/value fields.").optional(),
295
+ memberships: z3.array(MembershipInput).describe(
296
+ "Contact groups to add this new contact to at creation. For an EXISTING contact use modifyContactGroupMembers instead. Resolve ids via listContactGroups."
297
+ ).optional(),
298
+ personFields: z3.string().describe(
299
+ "Comma-separated list of contact fields to return (e.g. names,emailAddresses,phoneNumbers). Defaults to a comprehensive set; narrow it to reduce payload. Include metadata for the etag."
300
+ ).default(DEFAULT_PERSON_FIELDS)
301
+ }).strict().refine(
302
+ (i) => (i.names?.length ?? 0) > 0 || (i.emailAddresses?.length ?? 0) > 0 || (i.phoneNumbers?.length ?? 0) > 0,
303
+ {
304
+ message: "Provide at least one of names, emailAddresses, or phoneNumbers \u2014 a contact with no name and no contact method is not useful."
305
+ }
306
+ );
307
+ var definition2 = defineTool2({
308
+ name: "createContact",
309
+ title: "Create Contact",
310
+ description: "Create a new contact from structured name, email, phone, address, and organization fields. Provide at least a name or one contact method.",
311
+ inputSchema: inputSchema2,
312
+ outputSchema: PersonSchema,
313
+ annotations: {
314
+ readOnlyHint: false,
315
+ destructiveHint: false,
316
+ idempotentHint: false,
317
+ openWorldHint: true
318
+ },
319
+ connection: "google-contacts",
320
+ run: async (input, ctx) => {
321
+ const { personFields, memberships, ...sections } = input;
322
+ const body = {};
323
+ for (const [key, value] of Object.entries(sections)) {
324
+ if (value !== void 0) body[key] = value;
325
+ }
326
+ if (memberships !== void 0) {
327
+ body.memberships = memberships.map((m) => ({
328
+ contactGroupMembership: {
329
+ contactGroupResourceName: m.contactGroupResourceName
330
+ }
331
+ }));
332
+ }
333
+ const url = new URL(
334
+ "https://people.googleapis.com/v1/people:createContact"
335
+ );
336
+ url.searchParams.set("personFields", personFields);
337
+ const res = await ctx.fetch(url.toString(), {
338
+ method: "POST",
339
+ headers: { "Content-Type": "application/json" },
340
+ body: JSON.stringify(body)
341
+ });
342
+ await throwForGoogleContacts(res, "createContact");
343
+ return res.json();
344
+ }
345
+ });
346
+ var createContact_default = definition2;
347
+ await handleIfScriptMain2(import.meta, definition2, { connectionResolvers });
348
+
349
+ // scripts/createContactGroup.ts
350
+ import { defineTool as defineTool3, handleIfScriptMain as handleIfScriptMain3 } from "@zapier/connectors-sdk";
351
+ import { z as z4 } from "zod";
352
+ var inputSchema3 = z4.object({
353
+ name: z4.string().describe(
354
+ "The contact group (label) name. A duplicate name returns an already-exists error."
355
+ )
356
+ }).strict();
357
+ var definition3 = defineTool3({
358
+ name: "createContactGroup",
359
+ title: "Create Contact Group",
360
+ description: "Create a new user contact group (label). Returns the resourceName used to add members via modifyContactGroupMembers.",
361
+ inputSchema: inputSchema3,
362
+ outputSchema: ContactGroupSchema,
363
+ annotations: {
364
+ readOnlyHint: false,
365
+ destructiveHint: false,
366
+ idempotentHint: false,
367
+ openWorldHint: true
368
+ },
369
+ connection: "google-contacts",
370
+ run: async (input, ctx) => {
371
+ const res = await ctx.fetch(
372
+ "https://people.googleapis.com/v1/contactGroups",
373
+ {
374
+ method: "POST",
375
+ headers: { "Content-Type": "application/json" },
376
+ body: JSON.stringify({ contactGroup: { name: input.name } })
377
+ }
378
+ );
379
+ await throwForGoogleContacts(res, "createContactGroup");
380
+ return res.json();
381
+ }
382
+ });
383
+ var createContactGroup_default = definition3;
384
+ await handleIfScriptMain3(import.meta, definition3, { connectionResolvers });
385
+
386
+ // scripts/deleteContact.ts
387
+ import { defineTool as defineTool4, handleIfScriptMain as handleIfScriptMain4 } from "@zapier/connectors-sdk";
388
+ import { z as z5 } from "zod";
389
+ var inputSchema4 = z5.object({
390
+ resourceName: z5.string().describe(
391
+ "Contact resource name, e.g. people/c12345 (from listContacts or searchContacts). Pass it whole, including the people/ prefix."
392
+ )
393
+ }).strict();
394
+ var definition4 = defineTool4({
395
+ name: "deleteContact",
396
+ title: "Delete Contact",
397
+ description: "Delete a contact from the user's account. A 404 means nothing was deleted \u2014 the resourceName wasn't found (already deleted, or a wrong/typo'd id); it is NOT a success. Re-resolve the contact via searchContacts/listContacts before retrying.",
398
+ inputSchema: inputSchema4,
399
+ outputSchema: z5.object({
400
+ success: z5.boolean().describe(
401
+ "True when the contact was deleted (the API returns an empty body)."
402
+ )
403
+ }),
404
+ annotations: {
405
+ readOnlyHint: false,
406
+ destructiveHint: true,
407
+ // Not idempotent: a 404 (already-deleted or wrong id) throws rather than
408
+ // reporting success, so a blind retry isn't safe — the agent must re-resolve.
409
+ idempotentHint: false,
410
+ openWorldHint: true
411
+ },
412
+ connection: "google-contacts",
413
+ run: async (input, ctx) => {
414
+ const url = `https://people.googleapis.com/v1/${input.resourceName}:deleteContact`;
415
+ const res = await ctx.fetch(url, { method: "DELETE" });
416
+ await throwForGoogleContacts(res, "deleteContact");
417
+ return { success: true };
418
+ }
419
+ });
420
+ var deleteContact_default = definition4;
421
+ await handleIfScriptMain4(import.meta, definition4, { connectionResolvers });
422
+
423
+ // scripts/deleteContactGroup.ts
424
+ import { defineTool as defineTool5, handleIfScriptMain as handleIfScriptMain5 } from "@zapier/connectors-sdk";
425
+ import { z as z6 } from "zod";
426
+ var inputSchema5 = z6.object({
427
+ resourceName: z6.string().describe(
428
+ "Contact group resource name, e.g. contactGroups/1a2b3c (from listContactGroups). Pass it whole, including the contactGroups/ prefix."
429
+ ),
430
+ deleteContacts: z6.boolean().describe(
431
+ "When true, also delete the contacts that were in the group (not just the label). Defaults to false (label only)."
432
+ ).default(false)
433
+ }).strict();
434
+ var definition5 = defineTool5({
435
+ name: "deleteContactGroup",
436
+ title: "Delete Contact Group",
437
+ description: "Delete a user contact group (label). System groups (myContacts, starred) cannot be deleted. Optionally delete the member contacts too. A 404 means nothing was deleted \u2014 the resourceName wasn't found (already deleted, or a wrong id); it is NOT a success. Re-resolve via listContactGroups before retrying.",
438
+ inputSchema: inputSchema5,
439
+ outputSchema: z6.object({
440
+ success: z6.boolean().describe(
441
+ "True when the group was deleted (the API returns an empty body)."
442
+ )
443
+ }),
444
+ annotations: {
445
+ readOnlyHint: false,
446
+ destructiveHint: true,
447
+ // Not idempotent: a 404 (already-deleted or wrong id) throws rather than
448
+ // reporting success, so a blind retry isn't safe — the agent must re-resolve.
449
+ idempotentHint: false,
450
+ openWorldHint: true
451
+ },
452
+ connection: "google-contacts",
453
+ run: async (input, ctx) => {
454
+ const url = new URL(
455
+ `https://people.googleapis.com/v1/${input.resourceName}`
456
+ );
457
+ url.searchParams.set("deleteContacts", String(input.deleteContacts));
458
+ const res = await ctx.fetch(url.toString(), { method: "DELETE" });
459
+ await throwForGoogleContacts(res, "deleteContactGroup");
460
+ return { success: true };
461
+ }
462
+ });
463
+ var deleteContactGroup_default = definition5;
464
+ await handleIfScriptMain5(import.meta, definition5, { connectionResolvers });
465
+
466
+ // scripts/deleteContactPhoto.ts
467
+ import { defineTool as defineTool6, handleIfScriptMain as handleIfScriptMain6 } from "@zapier/connectors-sdk";
468
+ import { z as z7 } from "zod";
469
+ var inputSchema6 = z7.object({
470
+ resourceName: z7.string().describe(
471
+ "Contact resource name, e.g. people/c12345 (from listContacts or searchContacts). Pass it whole, including the people/ prefix."
472
+ ),
473
+ personFields: z7.string().describe(
474
+ "Comma-separated list of contact fields to return (e.g. names,emailAddresses,phoneNumbers). Defaults to a comprehensive set; narrow it to reduce payload. Include metadata for the etag."
475
+ ).default(DEFAULT_PERSON_FIELDS)
476
+ }).strict();
477
+ var definition6 = defineTool6({
478
+ name: "deleteContactPhoto",
479
+ title: "Delete Contact Photo",
480
+ description: "Remove a contact's photo, reverting to the default avatar.",
481
+ inputSchema: inputSchema6,
482
+ outputSchema: PersonResponseSchema,
483
+ annotations: {
484
+ readOnlyHint: false,
485
+ destructiveHint: true,
486
+ idempotentHint: true,
487
+ openWorldHint: true
488
+ },
489
+ connection: "google-contacts",
490
+ run: async (input, ctx) => {
491
+ const url = new URL(
492
+ `https://people.googleapis.com/v1/${input.resourceName}:deleteContactPhoto`
493
+ );
494
+ url.searchParams.set("personFields", input.personFields);
495
+ const res = await ctx.fetch(url.toString(), { method: "DELETE" });
496
+ await throwForGoogleContacts(res, "deleteContactPhoto");
497
+ return res.json();
498
+ }
499
+ });
500
+ var deleteContactPhoto_default = definition6;
501
+ await handleIfScriptMain6(import.meta, definition6, { connectionResolvers });
502
+
503
+ // scripts/getContact.ts
504
+ import { defineTool as defineTool7, handleIfScriptMain as handleIfScriptMain7 } from "@zapier/connectors-sdk";
505
+ import { z as z8 } from "zod";
506
+ var inputSchema7 = z8.object({
507
+ resourceName: z8.string().describe(
508
+ "Contact resource name, e.g. people/c12345 (from listContacts or searchContacts). Pass it whole, including the people/ prefix."
509
+ ),
510
+ personFields: z8.string().describe(
511
+ "Comma-separated list of contact fields to return (e.g. names,emailAddresses,phoneNumbers). Defaults to a comprehensive set; narrow it to reduce payload. Include metadata for the etag."
512
+ ).default(DEFAULT_PERSON_FIELDS)
513
+ }).strict();
514
+ var definition7 = defineTool7({
515
+ name: "getContact",
516
+ title: "Get Contact",
517
+ description: "Retrieve a single contact by resource name, with full field detail. Call before an additive update to read the existing arrays.",
518
+ inputSchema: inputSchema7,
519
+ outputSchema: PersonSchema,
520
+ annotations: {
521
+ readOnlyHint: true,
522
+ destructiveHint: false,
523
+ idempotentHint: true,
524
+ openWorldHint: true
525
+ },
526
+ connection: "google-contacts",
527
+ run: async (input, ctx) => {
528
+ const url = new URL(
529
+ `https://people.googleapis.com/v1/${input.resourceName}`
530
+ );
531
+ url.searchParams.set("personFields", input.personFields);
532
+ const res = await ctx.fetch(url.toString(), { method: "GET" });
533
+ await throwForGoogleContacts(res, "getContact");
534
+ return res.json();
535
+ }
536
+ });
537
+ var getContact_default = definition7;
538
+ await handleIfScriptMain7(import.meta, definition7, { connectionResolvers });
539
+
540
+ // scripts/getContactGroup.ts
541
+ import { defineTool as defineTool8, handleIfScriptMain as handleIfScriptMain8 } from "@zapier/connectors-sdk";
542
+ import { z as z9 } from "zod";
543
+ var inputSchema8 = z9.object({
544
+ resourceName: z9.string().describe(
545
+ "Contact group resource name, e.g. contactGroups/1a2b3c (from listContactGroups). Pass it whole, including the contactGroups/ prefix."
546
+ ),
547
+ maxMembers: z9.number().int().gte(1).describe(
548
+ "Include up to this many member contact resource names (people/c\u2026) in memberResourceNames. Omit to return group metadata only."
549
+ ).optional(),
550
+ groupFields: z9.string().describe(
551
+ "Comma-separated list of contact-group fields to return (e.g. name,groupType,memberCount)."
552
+ ).default(DEFAULT_GROUP_FIELDS)
553
+ }).strict();
554
+ var definition8 = defineTool8({
555
+ name: "getContactGroup",
556
+ title: "Get Contact Group",
557
+ description: "Get a single contact group (label) by resource name, optionally with its member contact resource names (set maxMembers).",
558
+ inputSchema: inputSchema8,
559
+ outputSchema: ContactGroupSchema,
560
+ annotations: {
561
+ readOnlyHint: true,
562
+ destructiveHint: false,
563
+ idempotentHint: true,
564
+ openWorldHint: true
565
+ },
566
+ connection: "google-contacts",
567
+ run: async (input, ctx) => {
568
+ const url = new URL(
569
+ `https://people.googleapis.com/v1/${input.resourceName}`
570
+ );
571
+ url.searchParams.set("groupFields", input.groupFields);
572
+ if (input.maxMembers !== void 0) {
573
+ url.searchParams.set("maxMembers", String(input.maxMembers));
574
+ }
575
+ const res = await ctx.fetch(url.toString(), { method: "GET" });
576
+ await throwForGoogleContacts(res, "getContactGroup");
577
+ return res.json();
578
+ }
579
+ });
580
+ var getContactGroup_default = definition8;
581
+ await handleIfScriptMain8(import.meta, definition8, { connectionResolvers });
582
+
583
+ // scripts/listContactGroups.ts
584
+ import { defineTool as defineTool9, handleIfScriptMain as handleIfScriptMain9 } from "@zapier/connectors-sdk";
585
+ import { z as z10 } from "zod";
586
+ var inputSchema9 = z10.object({
587
+ groupFields: z10.string().describe(
588
+ "Comma-separated list of contact-group fields to return (e.g. name,groupType,memberCount)."
589
+ ).default(DEFAULT_GROUP_FIELDS),
590
+ pageSize: z10.number().int().gte(1).lte(1e3).describe(
591
+ "Max groups to return per page. Defaults to 20 when omitted; pass a value when you need a specific number of results."
592
+ ).optional(),
593
+ pageToken: z10.string().describe(
594
+ "Page cursor from a previous response's next_page_token. Omit for the first page."
595
+ ).optional()
596
+ }).strict();
597
+ var definition9 = defineTool9({
598
+ name: "listContactGroups",
599
+ title: "List Contact Groups",
600
+ description: "List the account's contact groups (labels), user and system, with id, name, type, and member count. The resolver for any contactGroupResourceName.",
601
+ inputSchema: inputSchema9,
602
+ outputSchema: z10.object({
603
+ contactGroups: z10.array(ContactGroupSchema).optional().describe("The page of contact groups."),
604
+ next_page_token: z10.string().optional().describe("Cursor for the next page; absent when there are no more.")
605
+ }),
606
+ annotations: {
607
+ readOnlyHint: true,
608
+ destructiveHint: false,
609
+ idempotentHint: true,
610
+ openWorldHint: true
611
+ },
612
+ connection: "google-contacts",
613
+ run: async (input, ctx) => {
614
+ const url = new URL("https://people.googleapis.com/v1/contactGroups");
615
+ url.searchParams.set("groupFields", input.groupFields);
616
+ url.searchParams.set("pageSize", String(input.pageSize ?? 20));
617
+ if (input.pageToken !== void 0) {
618
+ url.searchParams.set("pageToken", input.pageToken);
619
+ }
620
+ const res = await ctx.fetch(url.toString(), { method: "GET" });
621
+ await throwForGoogleContacts(res, "listContactGroups");
622
+ const payload = await res.json();
623
+ if (payload && typeof payload === "object" && "nextPageToken" in payload) {
624
+ payload.next_page_token = payload.nextPageToken;
625
+ delete payload.nextPageToken;
626
+ }
627
+ return payload;
628
+ }
629
+ });
630
+ var listContactGroups_default = definition9;
631
+ await handleIfScriptMain9(import.meta, definition9, { connectionResolvers });
632
+
633
+ // scripts/listContacts.ts
634
+ import { defineTool as defineTool10, handleIfScriptMain as handleIfScriptMain10 } from "@zapier/connectors-sdk";
635
+ import { z as z11 } from "zod";
636
+ var inputSchema10 = z11.object({
637
+ personFields: z11.string().describe(
638
+ "Comma-separated list of contact fields to return (e.g. names,emailAddresses,phoneNumbers). Defaults to a comprehensive set; narrow it to reduce payload. Include metadata for the etag."
639
+ ).default(DEFAULT_PERSON_FIELDS),
640
+ sortOrder: z11.enum([
641
+ "LAST_MODIFIED_ASCENDING",
642
+ "LAST_MODIFIED_DESCENDING",
643
+ "FIRST_NAME_ASCENDING",
644
+ "LAST_NAME_ASCENDING"
645
+ ]).describe("Order of the returned contacts.").optional(),
646
+ pageSize: z11.number().int().gte(1).lte(1e3).describe(
647
+ "Max contacts to return per page. Defaults to 20 when omitted; pass a value when you need a specific number of results."
648
+ ).optional(),
649
+ pageToken: z11.string().describe(
650
+ "Page cursor from a previous response's next_page_token. Omit for the first page."
651
+ ).optional()
652
+ }).strict();
653
+ var definition10 = defineTool10({
654
+ name: "listContacts",
655
+ title: "List Contacts",
656
+ description: "List the user's contacts, paginated, with full field detail. The primary contact enumerator and resourceName resolver. Use this (not searchContacts) when freshness matters.",
657
+ inputSchema: inputSchema10,
658
+ outputSchema: z11.object({
659
+ contacts: z11.array(PersonSchema).optional().describe("The page of contacts."),
660
+ next_page_token: z11.string().optional().describe("Cursor for the next page; absent when there are no more."),
661
+ total_people: z11.number().int().optional().describe("Total contacts on the account.")
662
+ }),
663
+ annotations: {
664
+ readOnlyHint: true,
665
+ destructiveHint: false,
666
+ idempotentHint: true,
667
+ openWorldHint: true
668
+ },
669
+ connection: "google-contacts",
670
+ run: async (input, ctx) => {
671
+ const url = new URL(
672
+ "https://people.googleapis.com/v1/people/me/connections"
673
+ );
674
+ url.searchParams.set("personFields", input.personFields);
675
+ if (input.sortOrder !== void 0) {
676
+ url.searchParams.set("sortOrder", input.sortOrder);
677
+ }
678
+ url.searchParams.set("pageSize", String(input.pageSize ?? 20));
679
+ if (input.pageToken !== void 0) {
680
+ url.searchParams.set("pageToken", input.pageToken);
681
+ }
682
+ const res = await ctx.fetch(url.toString(), { method: "GET" });
683
+ await throwForGoogleContacts(res, "listContacts");
684
+ const payload = await res.json();
685
+ if (payload && typeof payload === "object") {
686
+ if ("connections" in payload) {
687
+ payload.contacts = payload.connections;
688
+ delete payload.connections;
689
+ }
690
+ if ("nextPageToken" in payload) {
691
+ payload.next_page_token = payload.nextPageToken;
692
+ delete payload.nextPageToken;
693
+ }
694
+ if ("totalPeople" in payload) {
695
+ payload.total_people = payload.totalPeople;
696
+ delete payload.totalPeople;
697
+ }
698
+ }
699
+ return payload;
700
+ }
701
+ });
702
+ var listContacts_default = definition10;
703
+ await handleIfScriptMain10(import.meta, definition10, { connectionResolvers });
704
+
705
+ // scripts/listOtherContacts.ts
706
+ import { defineTool as defineTool11, handleIfScriptMain as handleIfScriptMain11 } from "@zapier/connectors-sdk";
707
+ import { z as z12 } from "zod";
708
+ var inputSchema11 = z12.object({
709
+ readMask: z12.string().describe(
710
+ "Comma-separated fields to return. Other contacts support only emailAddresses, metadata, names, phoneNumbers, and photos."
711
+ ).default("names,emailAddresses,phoneNumbers,metadata"),
712
+ pageSize: z12.number().int().gte(1).lte(1e3).describe(
713
+ "Max other-contacts to return per page. Defaults to 20 when omitted; pass a value when you need a specific number of results."
714
+ ).optional(),
715
+ pageToken: z12.string().describe(
716
+ "Page cursor from a previous response's next_page_token. Omit for the first page."
717
+ ).optional()
718
+ }).strict();
719
+ var definition11 = defineTool11({
720
+ name: "listOtherContacts",
721
+ title: "List Other Contacts",
722
+ description: `List the user's auto-saved "other contacts" \u2014 people interacted with (e.g. emailed) but never explicitly saved. Read-only; use copyOtherContact to make one editable.`,
723
+ inputSchema: inputSchema11,
724
+ outputSchema: z12.object({
725
+ otherContacts: z12.array(PersonSchema).optional().describe("The page of other contacts."),
726
+ next_page_token: z12.string().optional().describe("Cursor for the next page; absent when there are no more.")
727
+ }),
728
+ annotations: {
729
+ readOnlyHint: true,
730
+ destructiveHint: false,
731
+ idempotentHint: true,
732
+ openWorldHint: true
733
+ },
734
+ connection: "google-contacts",
735
+ run: async (input, ctx) => {
736
+ const url = new URL("https://people.googleapis.com/v1/otherContacts");
737
+ url.searchParams.set("readMask", input.readMask);
738
+ url.searchParams.set("pageSize", String(input.pageSize ?? 20));
739
+ if (input.pageToken !== void 0) {
740
+ url.searchParams.set("pageToken", input.pageToken);
741
+ }
742
+ const res = await ctx.fetch(url.toString(), { method: "GET" });
743
+ await throwForGoogleContacts(res, "listOtherContacts");
744
+ const payload = await res.json();
745
+ if (payload && typeof payload === "object" && "nextPageToken" in payload) {
746
+ payload.next_page_token = payload.nextPageToken;
747
+ delete payload.nextPageToken;
748
+ }
749
+ return payload;
750
+ }
751
+ });
752
+ var listOtherContacts_default = definition11;
753
+ await handleIfScriptMain11(import.meta, definition11, { connectionResolvers });
754
+
755
+ // scripts/modifyContactGroupMembers.ts
756
+ import { defineTool as defineTool12, handleIfScriptMain as handleIfScriptMain12 } from "@zapier/connectors-sdk";
757
+ import { z as z13 } from "zod";
758
+ var inputSchema12 = z13.object({
759
+ resourceName: z13.string().describe(
760
+ "Contact group resource name, e.g. contactGroups/1a2b3c (from listContactGroups)."
761
+ ),
762
+ resourceNamesToAdd: z13.array(z13.string()).describe("Contact resource names (people/c\u2026) to add to the group.").optional(),
763
+ resourceNamesToRemove: z13.array(z13.string()).describe("Contact resource names (people/c\u2026) to remove from the group.").optional()
764
+ }).strict().refine(
765
+ (i) => (i.resourceNamesToAdd?.length ?? 0) > 0 || (i.resourceNamesToRemove?.length ?? 0) > 0,
766
+ {
767
+ message: "Provide at least one of resourceNamesToAdd or resourceNamesToRemove \u2014 both cannot be empty."
768
+ }
769
+ );
770
+ var definition12 = defineTool12({
771
+ name: "modifyContactGroupMembers",
772
+ title: "Modify Contact Group Members",
773
+ description: "Add and/or remove contacts in a contact group without disturbing other memberships. Combined add+remove must be 1000 or fewer.",
774
+ inputSchema: inputSchema12,
775
+ outputSchema: z13.object({
776
+ notFoundResourceNames: z13.array(z13.string()).optional().describe("Resource names that could not be found and were skipped."),
777
+ canNotRemoveLastContactGroupResourceNames: z13.array(z13.string()).optional().describe(
778
+ "Contacts that could not be removed because it was their only group (every contact stays in myContacts)."
779
+ )
780
+ }),
781
+ annotations: {
782
+ readOnlyHint: false,
783
+ // resourceNamesToRemove removes group memberships — a non-additive update.
784
+ destructiveHint: true,
785
+ idempotentHint: false,
786
+ openWorldHint: true
787
+ },
788
+ connection: "google-contacts",
789
+ run: async (input, ctx) => {
790
+ const url = `https://people.googleapis.com/v1/${input.resourceName}/members:modify`;
791
+ const body = {};
792
+ if (input.resourceNamesToAdd !== void 0)
793
+ body.resourceNamesToAdd = input.resourceNamesToAdd;
794
+ if (input.resourceNamesToRemove !== void 0)
795
+ body.resourceNamesToRemove = input.resourceNamesToRemove;
796
+ const res = await ctx.fetch(url, {
797
+ method: "POST",
798
+ headers: { "Content-Type": "application/json" },
799
+ body: JSON.stringify(body)
800
+ });
801
+ await throwForGoogleContacts(res, "modifyContactGroupMembers");
802
+ return res.json();
803
+ }
804
+ });
805
+ var modifyContactGroupMembers_default = definition12;
806
+ await handleIfScriptMain12(import.meta, definition12, { connectionResolvers });
807
+
808
+ // scripts/searchContacts.ts
809
+ import { defineTool as defineTool13, handleIfScriptMain as handleIfScriptMain13 } from "@zapier/connectors-sdk";
810
+ import { z as z14 } from "zod";
811
+ var inputSchema13 = z14.object({
812
+ query: z14.string().describe(
813
+ 'Prefix phrase matched against names, nicknames, emails, phones, and organizations. "foo n" matches "foo name"; "oo n" does not.'
814
+ ),
815
+ readMask: z14.string().describe(
816
+ "Comma-separated list of contact fields to return on each match. Defaults to a comprehensive set."
817
+ ).default(DEFAULT_PERSON_FIELDS),
818
+ pageSize: z14.number().int().gte(1).lte(30).describe(
819
+ "Max results per page. Caps at 30. Defaults to 10 when omitted; pass a value when you need a specific number of results."
820
+ ).optional()
821
+ }).strict();
822
+ var definition13 = defineTool13({
823
+ name: "searchContacts",
824
+ title: "Search Contacts",
825
+ description: "Search the user's contacts by name, nickname, email, phone, or organization (prefix matching). Newly created/updated contacts may lag a few minutes behind \u2014 use listContacts when freshness matters.",
826
+ inputSchema: inputSchema13,
827
+ outputSchema: z14.object({
828
+ results: z14.array(z14.object({ person: PersonSchema.optional() })).optional().describe("Matching contacts.")
829
+ }),
830
+ annotations: {
831
+ readOnlyHint: true,
832
+ destructiveHint: false,
833
+ idempotentHint: true,
834
+ openWorldHint: true
835
+ },
836
+ connection: "google-contacts",
837
+ run: async (input, ctx) => {
838
+ const url = new URL(
839
+ "https://people.googleapis.com/v1/people:searchContacts"
840
+ );
841
+ url.searchParams.set("query", input.query);
842
+ url.searchParams.set("readMask", input.readMask);
843
+ url.searchParams.set("pageSize", String(input.pageSize ?? 10));
844
+ const res = await ctx.fetch(url.toString(), { method: "GET" });
845
+ await throwForGoogleContacts(res, "searchContacts");
846
+ return res.json();
847
+ }
848
+ });
849
+ var searchContacts_default = definition13;
850
+ await handleIfScriptMain13(import.meta, definition13, { connectionResolvers });
851
+
852
+ // scripts/searchOtherContacts.ts
853
+ import { defineTool as defineTool14, handleIfScriptMain as handleIfScriptMain14 } from "@zapier/connectors-sdk";
854
+ import { z as z15 } from "zod";
855
+ var inputSchema14 = z15.object({
856
+ query: z15.string().describe(
857
+ "Prefix phrase matched against names, emails, and phones of other contacts."
858
+ ),
859
+ readMask: z15.string().describe(
860
+ "Comma-separated fields to return. Other contacts support only emailAddresses, metadata, names, phoneNumbers, and photos."
861
+ ).default("names,emailAddresses,phoneNumbers,metadata"),
862
+ pageSize: z15.number().int().gte(1).lte(30).describe(
863
+ "Max results per page. Caps at 30. Defaults to 10 when omitted; pass a value when you need a specific number of results."
864
+ ).optional()
865
+ }).strict();
866
+ var definition14 = defineTool14({
867
+ name: "searchOtherContacts",
868
+ title: "Search Other Contacts",
869
+ description: `Search the user's "other contacts" by name, email, or phone (prefix matching). Same lazy-index caveat as searchContacts \u2014 recently-seen contacts may lag.`,
870
+ inputSchema: inputSchema14,
871
+ outputSchema: z15.object({
872
+ results: z15.array(z15.object({ person: PersonSchema.optional() })).optional().describe("Matching other contacts.")
873
+ }),
874
+ annotations: {
875
+ readOnlyHint: true,
876
+ destructiveHint: false,
877
+ idempotentHint: true,
878
+ openWorldHint: true
879
+ },
880
+ connection: "google-contacts",
881
+ run: async (input, ctx) => {
882
+ const url = new URL(
883
+ "https://people.googleapis.com/v1/otherContacts:search"
884
+ );
885
+ url.searchParams.set("query", input.query);
886
+ url.searchParams.set("readMask", input.readMask);
887
+ url.searchParams.set("pageSize", String(input.pageSize ?? 10));
888
+ const res = await ctx.fetch(url.toString(), { method: "GET" });
889
+ await throwForGoogleContacts(res, "searchOtherContacts");
890
+ return res.json();
891
+ }
892
+ });
893
+ var searchOtherContacts_default = definition14;
894
+ await handleIfScriptMain14(import.meta, definition14, { connectionResolvers });
895
+
896
+ // scripts/updateContact.ts
897
+ import { defineTool as defineTool15, handleIfScriptMain as handleIfScriptMain15 } from "@zapier/connectors-sdk";
898
+ import { z as z16 } from "zod";
899
+ var inputSchema15 = z16.object({
900
+ resourceName: z16.string().describe(
901
+ "Contact to update, e.g. people/c12345 (from listContacts or searchContacts). Pass it whole, including the people/ prefix."
902
+ ),
903
+ names: z16.array(NameInput).describe(
904
+ "Replaces the full names array. unstructuredName is rebuilt from the parts if you omit it."
905
+ ).optional(),
906
+ emailAddresses: z16.array(EmailAddressInput).describe(
907
+ "Replaces the full email list. To add one without losing the others, getContact first, append, then send the complete array."
908
+ ).optional(),
909
+ phoneNumbers: z16.array(PhoneNumberInput).describe(
910
+ "Replaces the full phone list. To add one without losing the others, getContact first, append, then send the complete array."
911
+ ).optional(),
912
+ addresses: z16.array(AddressInput).describe("Replaces the full addresses array.").optional(),
913
+ organizations: z16.array(OrganizationInput).describe("Replaces the full organizations array.").optional(),
914
+ biographies: z16.array(BiographyInput).describe("Replaces the full notes (biographies) array.").optional(),
915
+ birthdays: z16.array(BirthdayInput).describe("Replaces the full birthdays array.").optional(),
916
+ urls: z16.array(UrlInput).describe("Replaces the full urls array.").optional(),
917
+ events: z16.array(ContactEventInput).describe("Replaces the full custom-events array.").optional(),
918
+ relations: z16.array(RelationInput).describe("Replaces the full relations array.").optional(),
919
+ userDefined: z16.array(UserDefinedInput).describe("Replaces the full userDefined key/value array.").optional()
920
+ }).strict();
921
+ function withUnstructuredNames(names) {
922
+ return names.map((n) => {
923
+ if (n.unstructuredName) return n;
924
+ const parts = [
925
+ n.honorificPrefix,
926
+ n.givenName,
927
+ n.middleName,
928
+ n.familyName,
929
+ n.honorificSuffix
930
+ ].filter((p) => Boolean(p && p.trim()));
931
+ if (parts.length === 0) return n;
932
+ return { ...n, unstructuredName: parts.join(" ") };
933
+ });
934
+ }
935
+ var definition15 = defineTool15({
936
+ name: "updateContact",
937
+ title: "Update Contact",
938
+ description: "Update fields on an existing contact. Each array you send REPLACES that whole field (e.g. sending emailAddresses replaces every email) \u2014 to add to a list, getContact first, append, then send the full array. Fields you omit are left untouched. Does not change group membership (use modifyContactGroupMembers).",
939
+ inputSchema: inputSchema15,
940
+ outputSchema: PersonSchema,
941
+ annotations: {
942
+ readOnlyHint: false,
943
+ // Each array field is replace-not-merge: sending one (e.g. emailAddresses)
944
+ // overwrites the whole field and silently drops any values not included.
945
+ // That is a non-additive (destructive) update, so the host should treat it
946
+ // as such and not suppress a confirmation.
947
+ destructiveHint: true,
948
+ idempotentHint: true,
949
+ openWorldHint: true
950
+ },
951
+ connection: "google-contacts",
952
+ run: async (input, ctx) => {
953
+ const { resourceName, ...fields } = input;
954
+ const updatePersonFields = deriveUpdatePersonFields(fields);
955
+ if (updatePersonFields === "") {
956
+ throw new Error(
957
+ "Google Contacts updateContact: no fields to update \u2014 supply at least one of names, emailAddresses, phoneNumbers, addresses, organizations, biographies, birthdays, urls, events, relations, or userDefined."
958
+ );
959
+ }
960
+ const getUrl = new URL(`https://people.googleapis.com/v1/${resourceName}`);
961
+ getUrl.searchParams.set("personFields", "metadata");
962
+ const getRes = await ctx.fetch(getUrl.toString(), { method: "GET" });
963
+ await throwForGoogleContacts(getRes, "updateContact");
964
+ const current = await getRes.json();
965
+ const body = { etag: current.etag, ...fields };
966
+ if (fields.names) body.names = withUnstructuredNames(fields.names);
967
+ const patchUrl = new URL(
968
+ `https://people.googleapis.com/v1/${resourceName}:updateContact`
969
+ );
970
+ patchUrl.searchParams.set("updatePersonFields", updatePersonFields);
971
+ patchUrl.searchParams.set("personFields", DEFAULT_PERSON_FIELDS);
972
+ const patchRes = await ctx.fetch(patchUrl.toString(), {
973
+ method: "PATCH",
974
+ headers: { "Content-Type": "application/json" },
975
+ body: JSON.stringify(body)
976
+ });
977
+ await throwForGoogleContacts(patchRes, "updateContact");
978
+ return patchRes.json();
979
+ }
980
+ });
981
+ var updateContact_default = definition15;
982
+ await handleIfScriptMain15(import.meta, definition15, { connectionResolvers });
983
+
984
+ // scripts/updateContactGroup.ts
985
+ import { defineTool as defineTool16, handleIfScriptMain as handleIfScriptMain16 } from "@zapier/connectors-sdk";
986
+ import { z as z17 } from "zod";
987
+ var inputSchema16 = z17.object({
988
+ resourceName: z17.string().describe(
989
+ "Contact group to rename, e.g. contactGroups/1a2b3c (from listContactGroups). System groups (myContacts, starred) cannot be renamed."
990
+ ),
991
+ name: z17.string().describe("The new contact group (label) name.")
992
+ }).strict();
993
+ var definition16 = defineTool16({
994
+ name: "updateContactGroup",
995
+ title: "Update Contact Group",
996
+ description: "Rename an existing user contact group (label). Only USER_CONTACT_GROUPs can be renamed \u2014 system groups (myContacts, starred) are rejected. Check groupType via listContactGroups.",
997
+ inputSchema: inputSchema16,
998
+ outputSchema: ContactGroupSchema,
999
+ annotations: {
1000
+ readOnlyHint: false,
1001
+ // Rename overwrites the existing group name (replace, not add) — non-additive.
1002
+ destructiveHint: true,
1003
+ idempotentHint: true,
1004
+ openWorldHint: true
1005
+ },
1006
+ connection: "google-contacts",
1007
+ run: async (input, ctx) => {
1008
+ const base = `https://people.googleapis.com/v1/${input.resourceName}`;
1009
+ const getUrl = new URL(base);
1010
+ getUrl.searchParams.set("groupFields", "metadata");
1011
+ const getRes = await ctx.fetch(getUrl.toString(), { method: "GET" });
1012
+ await throwForGoogleContacts(getRes, "updateContactGroup");
1013
+ const current = await getRes.json();
1014
+ const putRes = await ctx.fetch(base, {
1015
+ method: "PUT",
1016
+ headers: { "Content-Type": "application/json" },
1017
+ body: JSON.stringify({
1018
+ contactGroup: { etag: current.etag, name: input.name },
1019
+ updateGroupFields: "name"
1020
+ })
1021
+ });
1022
+ await throwForGoogleContacts(putRes, "updateContactGroup");
1023
+ return putRes.json();
1024
+ }
1025
+ });
1026
+ var updateContactGroup_default = definition16;
1027
+ await handleIfScriptMain16(import.meta, definition16, { connectionResolvers });
1028
+
1029
+ // scripts/updateContactPhoto.ts
1030
+ import { defineTool as defineTool17, handleIfScriptMain as handleIfScriptMain17 } from "@zapier/connectors-sdk";
1031
+ import { z as z18 } from "zod";
1032
+ var inputSchema17 = z18.object({
1033
+ resourceName: z18.string().describe(
1034
+ "Contact resource name, e.g. people/c12345 (from listContacts or searchContacts). Pass it whole, including the people/ prefix."
1035
+ ),
1036
+ photoBytes: z18.string().describe("The contact photo as a base64-encoded image string."),
1037
+ personFields: z18.string().describe(
1038
+ "Which fields to return on the updated contact. Defaults to a comprehensive set."
1039
+ ).default("names,emailAddresses,phoneNumbers,photos,metadata")
1040
+ }).strict();
1041
+ var definition17 = defineTool17({
1042
+ name: "updateContactPhoto",
1043
+ title: "Update Contact Photo",
1044
+ description: "Set or replace a contact's photo. photoBytes is the image as a base64-encoded string (not a URL or file path).",
1045
+ inputSchema: inputSchema17,
1046
+ outputSchema: PersonResponseSchema,
1047
+ annotations: {
1048
+ readOnlyHint: false,
1049
+ // Overwrites the contact's existing photo (replace, not add) — non-additive.
1050
+ destructiveHint: true,
1051
+ idempotentHint: true,
1052
+ openWorldHint: true
1053
+ },
1054
+ connection: "google-contacts",
1055
+ run: async (input, ctx) => {
1056
+ const url = `https://people.googleapis.com/v1/${input.resourceName}:updateContactPhoto`;
1057
+ const res = await ctx.fetch(url, {
1058
+ method: "PATCH",
1059
+ headers: { "Content-Type": "application/json" },
1060
+ body: JSON.stringify({
1061
+ photoBytes: input.photoBytes,
1062
+ personFields: input.personFields
1063
+ })
1064
+ });
1065
+ await throwForGoogleContacts(res, "updateContactPhoto");
1066
+ return res.json();
1067
+ }
1068
+ });
1069
+ var updateContactPhoto_default = definition17;
1070
+ await handleIfScriptMain17(import.meta, definition17, { connectionResolvers });
1071
+
1072
+ // index.ts
1073
+ var connector = defineConnector({
1074
+ scripts: {
1075
+ copyOtherContact: copyOtherContact_default,
1076
+ createContact: createContact_default,
1077
+ createContactGroup: createContactGroup_default,
1078
+ deleteContact: deleteContact_default,
1079
+ deleteContactGroup: deleteContactGroup_default,
1080
+ deleteContactPhoto: deleteContactPhoto_default,
1081
+ getContact: getContact_default,
1082
+ getContactGroup: getContactGroup_default,
1083
+ listContactGroups: listContactGroups_default,
1084
+ listContacts: listContacts_default,
1085
+ listOtherContacts: listOtherContacts_default,
1086
+ modifyContactGroupMembers: modifyContactGroupMembers_default,
1087
+ searchContacts: searchContacts_default,
1088
+ searchOtherContacts: searchOtherContacts_default,
1089
+ updateContact: updateContact_default,
1090
+ updateContactGroup: updateContactGroup_default,
1091
+ updateContactPhoto: updateContactPhoto_default
1092
+ },
1093
+ connectionResolvers
1094
+ });
1095
+ var index_default = connector;
1096
+ var {
1097
+ copyOtherContact,
1098
+ createContact,
1099
+ createContactGroup,
1100
+ deleteContact,
1101
+ deleteContactGroup,
1102
+ deleteContactPhoto,
1103
+ getContact,
1104
+ getContactGroup,
1105
+ listContactGroups,
1106
+ listContacts,
1107
+ listOtherContacts,
1108
+ modifyContactGroupMembers,
1109
+ searchContacts,
1110
+ searchOtherContacts,
1111
+ updateContact,
1112
+ updateContactGroup,
1113
+ updateContactPhoto
1114
+ } = toFunctions(connector);
1115
+ export {
1116
+ copyOtherContact,
1117
+ createContact,
1118
+ createContactGroup,
1119
+ index_default as default,
1120
+ deleteContact,
1121
+ deleteContactGroup,
1122
+ deleteContactPhoto,
1123
+ getContact,
1124
+ getContactGroup,
1125
+ listContactGroups,
1126
+ listContacts,
1127
+ listOtherContacts,
1128
+ modifyContactGroupMembers,
1129
+ searchContacts,
1130
+ searchOtherContacts,
1131
+ updateContact,
1132
+ updateContactGroup,
1133
+ updateContactPhoto
1134
+ };