@hasna/contacts 0.8.1 → 0.9.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.
Files changed (56) hide show
  1. package/README.md +10 -0
  2. package/dist/browser/cli.d.ts +4 -0
  3. package/dist/browser/cli.d.ts.map +1 -0
  4. package/dist/browser/identity.d.ts +3 -0
  5. package/dist/browser/identity.d.ts.map +1 -0
  6. package/dist/browser/install.d.ts +32 -0
  7. package/dist/browser/install.d.ts.map +1 -0
  8. package/dist/browser/native.d.ts +3 -0
  9. package/dist/browser/native.d.ts.map +1 -0
  10. package/dist/browser/native.js +822 -0
  11. package/dist/browser/protocol.d.ts +26 -0
  12. package/dist/browser/protocol.d.ts.map +1 -0
  13. package/dist/browser/values.d.ts +18 -0
  14. package/dist/browser/values.d.ts.map +1 -0
  15. package/dist/cli/commands/core.d.ts.map +1 -1
  16. package/dist/cli/index.js +408 -127
  17. package/dist/cli/status-domain.preload.d.ts +1 -1
  18. package/dist/cli/status-domain.preload.d.ts.map +1 -1
  19. package/dist/cli/status-fixture.d.ts +17 -0
  20. package/dist/cli/status-fixture.d.ts.map +1 -0
  21. package/dist/index.js +43 -4
  22. package/dist/lib/audience-contract.d.ts +9 -9
  23. package/dist/lib/compact-output.d.ts +67 -0
  24. package/dist/lib/compact-output.d.ts.map +1 -0
  25. package/dist/mcp/handlers/core.d.ts.map +1 -1
  26. package/dist/mcp/index.d.ts +2 -1
  27. package/dist/mcp/index.d.ts.map +1 -1
  28. package/dist/mcp/index.js +378 -194
  29. package/dist/mcp/profile.d.ts +8 -0
  30. package/dist/mcp/profile.d.ts.map +1 -0
  31. package/dist/mcp/register-tools.d.ts +3 -1
  32. package/dist/mcp/register-tools.d.ts.map +1 -1
  33. package/dist/mcp/storage-tools.d.ts +2 -1
  34. package/dist/mcp/storage-tools.d.ts.map +1 -1
  35. package/dist/mcp/tools.d.ts +7 -45
  36. package/dist/mcp/tools.d.ts.map +1 -1
  37. package/dist/sdk/index.js +1 -1
  38. package/dist/server/index.js +30 -16
  39. package/dist/server/pg-store.d.ts +1 -0
  40. package/dist/server/pg-store.d.ts.map +1 -1
  41. package/dist/store/index.d.ts.map +1 -1
  42. package/docs/chrome-autofill.md +45 -0
  43. package/extension/background.js +284 -0
  44. package/extension/content.js +392 -0
  45. package/extension/detect.js +228 -0
  46. package/extension/fill.js +112 -0
  47. package/extension/icons/128.png +0 -0
  48. package/extension/icons/16.png +0 -0
  49. package/extension/icons/32.png +0 -0
  50. package/extension/icons/48.png +0 -0
  51. package/extension/icons/icon.svg +7 -0
  52. package/extension/manifest.json +54 -0
  53. package/extension/popup.css +71 -0
  54. package/extension/popup.html +50 -0
  55. package/extension/popup.js +166 -0
  56. package/package.json +9 -5
@@ -1,2 +1,2 @@
1
- declare const originalFetch: typeof fetch;
1
+ export {};
2
2
  //# sourceMappingURL=status-domain.preload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status-domain.preload.d.ts","sourceRoot":"","sources":["../../src/cli/status-domain.preload.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,aAAa,cAAmB,CAAC"}
1
+ {"version":3,"file":"status-domain.preload.d.ts","sourceRoot":"","sources":["../../src/cli/status-domain.preload.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ export type StatusFixtureMode = "unconfigured" | "failure" | "success";
2
+ export declare const fixtureStation = "contacts-status-fixture";
3
+ export declare const envFixtureKey = "status-fixture-key";
4
+ export declare const diskFixtureKey = "disk-key-not-a-real-secret";
5
+ export declare function statusFixtureEnv(): Record<string, string>;
6
+ export declare function statusFixtureCommand(home: string, command: string[]): string[];
7
+ export declare function runStatusFixture(args: string[], env: Record<string, string>, mode?: StatusFixtureMode): {
8
+ exitCode: number | null;
9
+ pid: number;
10
+ output: (string | null)[];
11
+ stdout: string;
12
+ stderr: string;
13
+ status: number | null;
14
+ signal: NodeJS.Signals | null;
15
+ error?: Error;
16
+ };
17
+ //# sourceMappingURL=status-fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-fixture.d.ts","sourceRoot":"","sources":["../../src/cli/status-fixture.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AACvE,eAAO,MAAM,cAAc,4BAA4B,CAAC;AACxD,eAAO,MAAM,aAAa,uBAAuB,CAAC;AAClD,eAAO,MAAM,cAAc,+BAA+B,CAAC;AAE3D,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWzD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAuB9E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,GAAE,iBAAkC;;;;;;;;;EAYrH"}
package/dist/index.js CHANGED
@@ -316,6 +316,39 @@ function stripUndefined(input) {
316
316
  return out;
317
317
  }
318
318
 
319
+ class ContactsApiResponseError extends Error {
320
+ constructor(operation, detail) {
321
+ super(`contacts: malformed /v1 response for ${operation}: ${detail}`);
322
+ this.name = "ContactsApiResponseError";
323
+ }
324
+ }
325
+ function requireAppendedContact(response, contactId, collection, matchKey, value) {
326
+ const operation = collection === "emails" ? "addEmailToContact" : "addPhoneToContact";
327
+ const contact = pick(response, "contact");
328
+ if (!contact || typeof contact !== "object" || Array.isArray(contact)) {
329
+ throw new ContactsApiResponseError(operation, "expected an object at response.contact");
330
+ }
331
+ if (contact.id !== contactId) {
332
+ throw new ContactsApiResponseError(operation, "response.contact.id did not match the requested contact");
333
+ }
334
+ const items = contact[collection];
335
+ if (!Array.isArray(items)) {
336
+ throw new ContactsApiResponseError(operation, `response.contact.${collection} was not an array`);
337
+ }
338
+ const normalize = collection === "emails" ? (input) => input.toLowerCase() : (input) => input;
339
+ const wanted = normalize(value);
340
+ const appended = items.find((item) => {
341
+ if (!item || typeof item !== "object" || Array.isArray(item))
342
+ return false;
343
+ const record = item;
344
+ return typeof record.id === "string" && record.contact_id === contactId && typeof record[matchKey] === "string" && normalize(record[matchKey]) === wanted;
345
+ });
346
+ if (!appended) {
347
+ throw new ContactsApiResponseError(operation, `response.contact.${collection} did not contain the requested value`);
348
+ }
349
+ return contact;
350
+ }
351
+
319
352
  class ApiStore {
320
353
  client;
321
354
  mode = "api";
@@ -385,11 +418,17 @@ class ApiStore {
385
418
  async mergeContacts() {
386
419
  return unavailable("mergeContacts");
387
420
  }
388
- async addEmailToContact() {
389
- return unavailable("addEmailToContact");
421
+ async addEmailToContact(contactId, email) {
422
+ const res = await this.patch(`/contacts/${this.enc(contactId)}`, {
423
+ emails_add: [stripUndefined(email)]
424
+ });
425
+ return requireAppendedContact(res, contactId, "emails", "address", email.address);
390
426
  }
391
- async addPhoneToContact() {
392
- return unavailable("addPhoneToContact");
427
+ async addPhoneToContact(contactId, phone) {
428
+ const res = await this.patch(`/contacts/${this.enc(contactId)}`, {
429
+ phones_add: [stripUndefined(phone)]
430
+ });
431
+ return requireAppendedContact(res, contactId, "phones", "number", phone.number);
393
432
  }
394
433
  async archiveContact() {
395
434
  return unavailable("archiveContact");
@@ -19,8 +19,8 @@ export declare const AudiencePredicateContractSchema: z.ZodEffects<z.ZodObject<{
19
19
  values: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
20
20
  }, "strict", z.ZodTypeAny, {
21
21
  values: (string | number | boolean)[];
22
- kind: "tag" | "attribute" | "group";
23
22
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
23
+ kind: "tag" | "attribute" | "group";
24
24
  key?: string | undefined;
25
25
  value?: string | number | boolean | undefined;
26
26
  }, {
@@ -31,8 +31,8 @@ export declare const AudiencePredicateContractSchema: z.ZodEffects<z.ZodObject<{
31
31
  op?: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists" | undefined;
32
32
  }>, {
33
33
  values: (string | number | boolean)[];
34
- kind: "tag" | "attribute" | "group";
35
34
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
35
+ kind: "tag" | "attribute" | "group";
36
36
  key?: string | undefined;
37
37
  value?: string | number | boolean | undefined;
38
38
  }, {
@@ -52,8 +52,8 @@ export declare const AudienceDefinitionContractSchema: z.ZodObject<{
52
52
  values: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
53
53
  }, "strict", z.ZodTypeAny, {
54
54
  values: (string | number | boolean)[];
55
- kind: "tag" | "attribute" | "group";
56
55
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
56
+ kind: "tag" | "attribute" | "group";
57
57
  key?: string | undefined;
58
58
  value?: string | number | boolean | undefined;
59
59
  }, {
@@ -64,8 +64,8 @@ export declare const AudienceDefinitionContractSchema: z.ZodObject<{
64
64
  op?: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists" | undefined;
65
65
  }>, {
66
66
  values: (string | number | boolean)[];
67
- kind: "tag" | "attribute" | "group";
68
67
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
68
+ kind: "tag" | "attribute" | "group";
69
69
  key?: string | undefined;
70
70
  value?: string | number | boolean | undefined;
71
71
  }, {
@@ -79,8 +79,8 @@ export declare const AudienceDefinitionContractSchema: z.ZodObject<{
79
79
  match: "all" | "any";
80
80
  predicates: {
81
81
  values: (string | number | boolean)[];
82
- kind: "tag" | "attribute" | "group";
83
82
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
83
+ kind: "tag" | "attribute" | "group";
84
84
  key?: string | undefined;
85
85
  value?: string | number | boolean | undefined;
86
86
  }[];
@@ -113,8 +113,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
113
113
  values: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
114
114
  }, "strict", z.ZodTypeAny, {
115
115
  values: (string | number | boolean)[];
116
- kind: "tag" | "attribute" | "group";
117
116
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
117
+ kind: "tag" | "attribute" | "group";
118
118
  key?: string | undefined;
119
119
  value?: string | number | boolean | undefined;
120
120
  }, {
@@ -125,8 +125,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
125
125
  op?: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists" | undefined;
126
126
  }>, {
127
127
  values: (string | number | boolean)[];
128
- kind: "tag" | "attribute" | "group";
129
128
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
129
+ kind: "tag" | "attribute" | "group";
130
130
  key?: string | undefined;
131
131
  value?: string | number | boolean | undefined;
132
132
  }, {
@@ -140,8 +140,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
140
140
  match: "all" | "any";
141
141
  predicates: {
142
142
  values: (string | number | boolean)[];
143
- kind: "tag" | "attribute" | "group";
144
143
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
144
+ kind: "tag" | "attribute" | "group";
145
145
  key?: string | undefined;
146
146
  value?: string | number | boolean | undefined;
147
147
  }[];
@@ -167,8 +167,8 @@ export declare const AudienceContractSchema: z.ZodObject<{
167
167
  match: "all" | "any";
168
168
  predicates: {
169
169
  values: (string | number | boolean)[];
170
- kind: "tag" | "attribute" | "group";
171
170
  op: "eq" | "neq" | "in" | "not_in" | "exists" | "not_exists";
171
+ kind: "tag" | "attribute" | "group";
172
172
  key?: string | undefined;
173
173
  value?: string | number | boolean | undefined;
174
174
  }[];
@@ -0,0 +1,67 @@
1
+ import type { ContactWithDetails } from "../types/index.js";
2
+ export declare const CONTACTS_COMPACT_LIMIT = 20;
3
+ export declare const CONTACTS_MAX_LIMIT = 500;
4
+ export declare function normalizeContactsLimit(value: unknown, fallback?: number): number;
5
+ export declare function normalizeContactsOffset(value: unknown): number;
6
+ export declare function summarizeContact(contact: ContactWithDetails): {
7
+ id: string;
8
+ display_name: string;
9
+ job_title: string | null;
10
+ company: {
11
+ id: string;
12
+ name: string;
13
+ } | null;
14
+ primary_email: string;
15
+ primary_phone: string;
16
+ status: import("../index.js").ContactStatus;
17
+ follow_up_at: string | null;
18
+ last_contacted_at: string | null;
19
+ archived: boolean;
20
+ sensitivity: import("../index.js").Sensitivity;
21
+ tags: {
22
+ id: string;
23
+ name: string;
24
+ }[];
25
+ updated_at: string;
26
+ };
27
+ export declare function compareContactsByDisplayNameAndId(left: Pick<ContactWithDetails, "display_name" | "id">, right: Pick<ContactWithDetails, "display_name" | "id">): number;
28
+ export declare function compactContactsPage(contacts: ContactWithDetails[], options: {
29
+ total: number;
30
+ limit: number;
31
+ offset: number;
32
+ }): {
33
+ contacts: {
34
+ id: string;
35
+ display_name: string;
36
+ job_title: string | null;
37
+ company: {
38
+ id: string;
39
+ name: string;
40
+ } | null;
41
+ primary_email: string;
42
+ primary_phone: string;
43
+ status: import("../index.js").ContactStatus;
44
+ follow_up_at: string | null;
45
+ last_contacted_at: string | null;
46
+ archived: boolean;
47
+ sensitivity: import("../index.js").Sensitivity;
48
+ tags: {
49
+ id: string;
50
+ name: string;
51
+ }[];
52
+ updated_at: string;
53
+ }[];
54
+ count: number;
55
+ total: number;
56
+ limit: number;
57
+ cursor: number;
58
+ next_cursor: number | null;
59
+ has_more: boolean;
60
+ compact: true;
61
+ sort: {
62
+ fields: string[];
63
+ direction: "asc";
64
+ };
65
+ hint: string;
66
+ };
67
+ //# sourceMappingURL=compact-output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-output.d.ts","sourceRoot":"","sources":["../../src/lib/compact-output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAyB,GAAG,MAAM,CAIhG;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI9D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB;;;;;;;;;;;;;;;;;;;;EAgB3D;AAED,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI,CAAC,EACrD,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI,CAAC,GACrD,MAAM,CAER;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,kBAAkB,EAAE,EAC9B,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkB1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/mcp/handlers/core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA2C9C,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CA+YpD,CAAC"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/mcp/handlers/core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4C9C,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CA0YpD,CAAC"}
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- export declare function buildServer(): McpServer;
3
+ import { type ContactsMcpProfile } from "./profile.js";
4
+ export declare function buildServer(profile?: ContactsMcpProfile): McpServer;
4
5
  /**
5
6
  * Classify early-exit arguments before any http-mode parse, server build, or
6
7
  * stdio bind. `--help` / `--version` answer with rc=0 and the MCP server never
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiBpE,wBAAgB,WAAW,IAAI,SAAS,CAKvC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAI5E;AAED,wBAAgB,QAAQ,IAAI,MAAM,CASjC;AA0CD,wBAAgB,gBAAgB,CAAC,KAAK,SAAkB,GAAG,OAAO,CAIjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,OAAO,EAA6B,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAYlF,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAA2B,GAAG,SAAS,CAQ3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAI5E;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAWjC;AA4CD,wBAAgB,gBAAgB,CAAC,KAAK,SAAkB,GAAG,OAAO,CAIjE"}