@dench.com/cli 3.6.3-staging.372 → 3.6.5-staging.384
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/README.md +16 -0
- package/agent-config.ts +10 -16
- package/app-sdk.d.ts +234 -6
- package/crm.ts +62 -16
- package/dench.ts +70 -36
- package/email.ts +207 -2
- package/lib/api-schemas.ts +127 -9
- package/lib/app-sdk-catalog.generated.ts +17 -0
- package/lib/app-sdk-surface.ts +49 -0
- package/lib/command-registry.ts +115 -3
- package/lib/enrichment-gateway.ts +12 -182
- package/lib/enrichment-shapes.ts +182 -0
- package/lib/native-providers.ts +44 -0
- package/package.json +1 -1
- package/tools.ts +106 -61
|
@@ -106,6 +106,7 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
106
106
|
{"id":"auth.otp.start","group":"auth","summary":"Start the email OTP sign-in flow.","cli":"dench signin --email","method":"POST","path":"/auth/otp/start","permission":"auth:write","pathParams":[]},
|
|
107
107
|
{"id":"auth.otp.verify","group":"auth","summary":"Verify an email OTP sign-in code.","cli":"dench signin --email","method":"POST","path":"/auth/otp/verify","permission":"auth:write","pathParams":[]},
|
|
108
108
|
{"id":"auth.otp.finalize","group":"auth","summary":"Finalize an email OTP sign-in session.","cli":"dench signin --email","method":"POST","path":"/auth/otp/finalize","permission":"auth:write","pathParams":[]},
|
|
109
|
+
{"id":"workspace.context.sections","group":"workspace","summary":"Read selected scoped workspace documents and a compact context index without writes.","cli":"dench context --sections","method":"GET","path":"/context/sections","permission":"workspace:read","pathParams":[]},
|
|
109
110
|
{"id":"workspace.context","group":"workspace","summary":"Return the current Dench workspace context for the bearer.","cli":"dench context","method":"GET","path":"/context","permission":"workspace:read","pathParams":[]},
|
|
110
111
|
{"id":"workspace.instructions","group":"workspace","summary":"Return the current workspace's standing instructions for external agents.","cli":"dench context --instructions","method":"GET","path":"/context/instructions","permission":"workspace:read","pathParams":[]},
|
|
111
112
|
{"id":"workspace.status","group":"workspace","summary":"Return workspace and agent status.","cli":"dench status","method":"GET","path":"/status","permission":"workspace:read","pathParams":[]},
|
|
@@ -314,6 +315,14 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
314
315
|
{"id":"email.identity.disable","group":"email","summary":"Soft-disable a sender (or every sender on a domain) for the workspace; sends are blocked until restored.","cli":"dench email identity disable","method":"POST","path":"/email/sending-identities/{identity}/disable","permission":"email:write","pathParams":["identity"]},
|
|
315
316
|
{"id":"email.identity.restore","group":"email","summary":"Restore a previously disabled sender for the workspace.","cli":"dench email identity restore","method":"POST","path":"/email/sending-identities/{identity}/restore","permission":"email:write","pathParams":["identity"]},
|
|
316
317
|
{"id":"email.identity.delete","group":"email","summary":"Permanently delete a sender (or every sender on a domain) from the workspace; re-adding it requires verification from scratch.","cli":"dench email identity delete","method":"DELETE","path":"/email/sending-identities/{identity}","permission":"email:write","pathParams":["identity"]},
|
|
318
|
+
{"id":"email.drafts.create","group":"email","summary":"Create an editable Dench email draft and synchronize its selected native mailbox asynchronously. Use a stable requestId for retries.","cli":"dench email draft create","method":"POST","path":"/email/drafts","permission":"email:write","pathParams":[]},
|
|
319
|
+
{"id":"email.drafts.get","group":"email","summary":"Read an email draft, eligible senders and provider sync status.","cli":"dench email draft show","method":"GET","path":"/email/drafts/{draftId}","permission":"email:read","pathParams":["draftId"]},
|
|
320
|
+
{"id":"email.drafts.senders","group":"email","summary":"List native mailboxes this caller may use.","cli":"dench email draft senders","method":"GET","path":"/email/drafts/senders","permission":"email:read","pathParams":[]},
|
|
321
|
+
{"id":"email.drafts.update","group":"email","summary":"Save draft content using expectedRevision; sender changes require a new draft after provider binding.","cli":"dench email draft update","method":"PATCH","path":"/email/drafts/{draftId}","permission":"email:write","pathParams":["draftId"]},
|
|
322
|
+
{"id":"email.drafts.send","group":"email","summary":"Send the current Dench draft revision through its native mailbox. Repeated requests share a durable receipt.","cli":"dench email draft send","method":"POST","path":"/email/drafts/{draftId}/send","permission":"email:write","pathParams":["draftId"]},
|
|
323
|
+
{"id":"email.drafts.upload","group":"email","summary":"Upload attachment bytes authorized against this draft before adding its storage reference.","cli":"dench email draft attach","method":"POST","path":"/email/drafts/{draftId}/attachments","permission":"email:write","pathParams":["draftId"]},
|
|
324
|
+
{"id":"email.drafts.signature","group":"email","summary":"Load the selected mailbox signature for explicit visible insertion.","cli":"dench email draft signature","method":"GET","path":"/email/drafts/{draftId}/signature","permission":"email:read","pathParams":["draftId"]},
|
|
325
|
+
{"id":"email.native.send","group":"email","summary":"Send through a native Gmail or Outlook mailbox with a durable request receipt. Only use for an explicit send request.","cli":"dench email send --mailbox","method":"POST","path":"/email/native/send","permission":"email:write","pathParams":[]},
|
|
317
326
|
{"id":"email.send","group":"email","summary":"Send one raw email (no campaign): to/cc/bcc, custom from-name and reply-to, optional reply threading via replyToMessageId.","cli":"dench email send","method":"POST","path":"/email/send","permission":"email:write","pathParams":[]},
|
|
318
327
|
{"id":"email.message.get","group":"email","summary":"Read a raw email message's status and open/click counters.","cli":"dench email message status","method":"GET","path":"/email/messages/{messageId}","permission":"email:read","pathParams":["messageId"]},
|
|
319
328
|
{"id":"email.message.list","group":"email","summary":"List recent raw email messages for the workspace.","cli":"dench email message list","method":"GET","path":"/email/messages","permission":"email:read","pathParams":[]},
|
|
@@ -608,6 +617,14 @@ export const APP_SDK_METHODS: Readonly<Record<string, AppSdkMethodInfo>> = {
|
|
|
608
617
|
"campaigns.campaignsForRecord": {"kind":"op","permission":"campaigns:read","op":"campaigns.people.forRecord","doc":"The campaigns a CRM record is in, with its status in each."},
|
|
609
618
|
"campaigns.personTimeline": {"kind":"op","permission":"campaigns:read","op":"campaigns.people.timeline","doc":"Everything a campaign did for one person, step by step."},
|
|
610
619
|
"campaigns.removePerson": {"kind":"op","permission":"campaigns:write","op":"campaigns.people.remove","doc":"Remove a never-contacted person from a draft campaign."},
|
|
620
|
+
"email.createDraft": {"kind":"op","permission":"email:write","op":"email.drafts.create","doc":"Create a native mailbox draft with a stable request receipt."},
|
|
621
|
+
"email.draft": {"kind":"op","permission":"email:read","op":"email.drafts.get","doc":"Read a native email draft and sync status."},
|
|
622
|
+
"email.updateDraft": {"kind":"op","permission":"email:write","op":"email.drafts.update","doc":"Save the next email draft revision."},
|
|
623
|
+
"email.sendDraft": {"kind":"op","permission":"email:write","op":"email.drafts.send","doc":"Send the frozen native email draft revision."},
|
|
624
|
+
"email.senders": {"kind":"op","permission":"email:read","op":"email.drafts.senders","doc":"List eligible native mailboxes."},
|
|
625
|
+
"email.uploadAttachment": {"kind":"op","permission":"email:write","op":"email.drafts.upload","doc":"Upload attachment bytes for a native draft."},
|
|
626
|
+
"email.signature": {"kind":"op","permission":"email:read","op":"email.drafts.signature","doc":"Load the selected mailbox signature for visible insertion."},
|
|
627
|
+
"email.sendFromMailbox": {"kind":"op","permission":"email:write","op":"email.native.send","doc":"Explicitly send through a native Gmail or Outlook mailbox."},
|
|
611
628
|
"email.send": {"kind":"op","permission":"email:write","op":"email.send","doc":"Send one email from a verified identity."},
|
|
612
629
|
"email.messages": {"kind":"op","permission":"email:read","op":"email.message.list","doc":"Sent messages."},
|
|
613
630
|
"email.message": {"kind":"op","permission":"email:read","op":"email.message.get","doc":"One sent message with delivery events."},
|
package/lib/app-sdk-surface.ts
CHANGED
|
@@ -908,6 +908,55 @@ export const APP_SDK_SURFACE: AppSdkSurface = {
|
|
|
908
908
|
},
|
|
909
909
|
|
|
910
910
|
email: {
|
|
911
|
+
createDraft: {
|
|
912
|
+
op: "email.drafts.create",
|
|
913
|
+
doc: "Create a native mailbox draft with a stable request receipt.",
|
|
914
|
+
args: `draft: ${A("email.drafts.create")}`,
|
|
915
|
+
returns: R("email.drafts.create"),
|
|
916
|
+
},
|
|
917
|
+
draft: {
|
|
918
|
+
op: "email.drafts.get",
|
|
919
|
+
doc: "Read a native email draft and sync status.",
|
|
920
|
+
args: "draftId: string",
|
|
921
|
+
returns: R("email.drafts.get"),
|
|
922
|
+
},
|
|
923
|
+
updateDraft: {
|
|
924
|
+
op: "email.drafts.update",
|
|
925
|
+
doc: "Save the next email draft revision.",
|
|
926
|
+
args: `input: ${A("email.drafts.update")}`,
|
|
927
|
+
returns: R("email.drafts.update"),
|
|
928
|
+
},
|
|
929
|
+
sendDraft: {
|
|
930
|
+
op: "email.drafts.send",
|
|
931
|
+
doc: "Send the frozen native email draft revision.",
|
|
932
|
+
args: `input: ${A("email.drafts.send")}`,
|
|
933
|
+
returns: R("email.drafts.send"),
|
|
934
|
+
},
|
|
935
|
+
senders: {
|
|
936
|
+
op: "email.drafts.senders",
|
|
937
|
+
doc: "List eligible native mailboxes.",
|
|
938
|
+
args: `opts?: ${A("email.drafts.senders")}`,
|
|
939
|
+
returns: R("email.drafts.senders"),
|
|
940
|
+
},
|
|
941
|
+
uploadAttachment: {
|
|
942
|
+
op: "email.drafts.upload",
|
|
943
|
+
doc: "Upload attachment bytes for a native draft.",
|
|
944
|
+
args: `input: ${A("email.drafts.upload")}`,
|
|
945
|
+
returns: R("email.drafts.upload"),
|
|
946
|
+
},
|
|
947
|
+
signature: {
|
|
948
|
+
op: "email.drafts.signature",
|
|
949
|
+
doc: "Load the selected mailbox signature for visible insertion.",
|
|
950
|
+
args: "draftId: string",
|
|
951
|
+
returns: R("email.drafts.signature"),
|
|
952
|
+
},
|
|
953
|
+
sendFromMailbox: {
|
|
954
|
+
op: "email.native.send",
|
|
955
|
+
doc: "Explicitly send through a native Gmail or Outlook mailbox.",
|
|
956
|
+
args: `message: ${A("email.native.send")}`,
|
|
957
|
+
returns: R("email.native.send"),
|
|
958
|
+
},
|
|
959
|
+
|
|
911
960
|
send: {
|
|
912
961
|
op: "email.send",
|
|
913
962
|
doc: "Send one email from a verified identity.",
|
package/lib/command-registry.ts
CHANGED
|
@@ -34,6 +34,9 @@ export type CustomOperation = {
|
|
|
34
34
|
| "cronRunNow"
|
|
35
35
|
| "connectionsList"
|
|
36
36
|
| "toolDisconnect"
|
|
37
|
+
| "nativeToolSearch"
|
|
38
|
+
| "nativeToolRun"
|
|
39
|
+
| "nativeToolConnect"
|
|
37
40
|
| "billingTopup"
|
|
38
41
|
| "upgrade"
|
|
39
42
|
| "filesMove"
|
|
@@ -468,6 +471,18 @@ const rawApiOperations = [
|
|
|
468
471
|
backend: local("Backend selection is local CLI state."),
|
|
469
472
|
}),
|
|
470
473
|
|
|
474
|
+
op({
|
|
475
|
+
id: "workspace.context.sections",
|
|
476
|
+
group: "workspace",
|
|
477
|
+
summary:
|
|
478
|
+
"Read selected scoped workspace documents and a compact context index without writes.",
|
|
479
|
+
cli: "dench context --sections",
|
|
480
|
+
method: "GET",
|
|
481
|
+
path: "/context/sections",
|
|
482
|
+
requestSchema: anyObject,
|
|
483
|
+
responseSchema: anyResponse,
|
|
484
|
+
backend: convex("query", "functions/agentConfig:workspaceContext"),
|
|
485
|
+
}),
|
|
471
486
|
// Workspace orientation.
|
|
472
487
|
op({
|
|
473
488
|
id: "workspace.context",
|
|
@@ -3332,6 +3347,103 @@ const rawApiOperations = [
|
|
|
3332
3347
|
responseSchema: anyResponse,
|
|
3333
3348
|
backend: convex("mutation", "functions/emailCampaigns:deleteIdentity"),
|
|
3334
3349
|
}),
|
|
3350
|
+
op({
|
|
3351
|
+
id: "email.drafts.create",
|
|
3352
|
+
group: "email",
|
|
3353
|
+
summary:
|
|
3354
|
+
"Create an editable Dench email draft and synchronize its selected native mailbox asynchronously. Use a stable requestId for retries.",
|
|
3355
|
+
cli: "dench email draft create",
|
|
3356
|
+
method: "POST",
|
|
3357
|
+
path: "/email/drafts",
|
|
3358
|
+
requestSchema: anyObject,
|
|
3359
|
+
responseSchema: anyResponse,
|
|
3360
|
+
backend: convex("mutation", "functions/emailDrafts:create"),
|
|
3361
|
+
}),
|
|
3362
|
+
op({
|
|
3363
|
+
id: "email.drafts.get",
|
|
3364
|
+
group: "email",
|
|
3365
|
+
summary: "Read an email draft, eligible senders and provider sync status.",
|
|
3366
|
+
cli: "dench email draft show",
|
|
3367
|
+
method: "GET",
|
|
3368
|
+
path: "/email/drafts/{draftId}",
|
|
3369
|
+
requestSchema: anyObject,
|
|
3370
|
+
responseSchema: anyResponse,
|
|
3371
|
+
backend: convex("query", "functions/emailDrafts:get"),
|
|
3372
|
+
}),
|
|
3373
|
+
op({
|
|
3374
|
+
id: "email.drafts.senders",
|
|
3375
|
+
group: "email",
|
|
3376
|
+
summary: "List native mailboxes this caller may use.",
|
|
3377
|
+
cli: "dench email draft senders",
|
|
3378
|
+
method: "GET",
|
|
3379
|
+
path: "/email/drafts/senders",
|
|
3380
|
+
requestSchema: anyObject,
|
|
3381
|
+
responseSchema: anyResponse,
|
|
3382
|
+
backend: convex("query", "functions/emailDrafts:listSenders"),
|
|
3383
|
+
}),
|
|
3384
|
+
op({
|
|
3385
|
+
id: "email.drafts.update",
|
|
3386
|
+
group: "email",
|
|
3387
|
+
summary:
|
|
3388
|
+
"Save draft content using expectedRevision; sender changes require a new draft after provider binding.",
|
|
3389
|
+
cli: "dench email draft update",
|
|
3390
|
+
method: "PATCH",
|
|
3391
|
+
path: "/email/drafts/{draftId}",
|
|
3392
|
+
requestSchema: anyObject,
|
|
3393
|
+
responseSchema: anyResponse,
|
|
3394
|
+
backend: convex("mutation", "functions/emailDrafts:update"),
|
|
3395
|
+
}),
|
|
3396
|
+
op({
|
|
3397
|
+
id: "email.drafts.send",
|
|
3398
|
+
group: "email",
|
|
3399
|
+
summary:
|
|
3400
|
+
"Send the current Dench draft revision through its native mailbox. Repeated requests share a durable receipt.",
|
|
3401
|
+
cli: "dench email draft send",
|
|
3402
|
+
method: "POST",
|
|
3403
|
+
path: "/email/drafts/{draftId}/send",
|
|
3404
|
+
requestSchema: anyObject,
|
|
3405
|
+
responseSchema: anyResponse,
|
|
3406
|
+
backend: convex("mutation", "functions/emailDrafts:send"),
|
|
3407
|
+
}),
|
|
3408
|
+
op({
|
|
3409
|
+
id: "email.drafts.upload",
|
|
3410
|
+
group: "email",
|
|
3411
|
+
summary:
|
|
3412
|
+
"Upload attachment bytes authorized against this draft before adding its storage reference.",
|
|
3413
|
+
cli: "dench email draft attach",
|
|
3414
|
+
method: "POST",
|
|
3415
|
+
path: "/email/drafts/{draftId}/attachments",
|
|
3416
|
+
requestSchema: anyObject,
|
|
3417
|
+
responseSchema: anyResponse,
|
|
3418
|
+
backend: convex("action", "functions/emailDraftsNode:uploadAttachment"),
|
|
3419
|
+
}),
|
|
3420
|
+
op({
|
|
3421
|
+
id: "email.drafts.signature",
|
|
3422
|
+
group: "email",
|
|
3423
|
+
summary:
|
|
3424
|
+
"Load the selected mailbox signature for explicit visible insertion.",
|
|
3425
|
+
cli: "dench email draft signature",
|
|
3426
|
+
method: "GET",
|
|
3427
|
+
path: "/email/drafts/{draftId}/signature",
|
|
3428
|
+
requestSchema: anyObject,
|
|
3429
|
+
responseSchema: anyResponse,
|
|
3430
|
+
backend: convex("action", "functions/emailDraftsNode:loadSignature"),
|
|
3431
|
+
}),
|
|
3432
|
+
op({
|
|
3433
|
+
id: "email.native.send",
|
|
3434
|
+
group: "email",
|
|
3435
|
+
summary:
|
|
3436
|
+
"Send through a native Gmail or Outlook mailbox with a durable request receipt. Only use for an explicit send request.",
|
|
3437
|
+
cli: "dench email send --mailbox",
|
|
3438
|
+
method: "POST",
|
|
3439
|
+
path: "/email/native/send",
|
|
3440
|
+
requestSchema: anyObject,
|
|
3441
|
+
responseSchema: anyResponse,
|
|
3442
|
+
backend: {
|
|
3443
|
+
...convex("mutation", "functions/emailDrafts:create"),
|
|
3444
|
+
fixedArgs: { mode: "send" },
|
|
3445
|
+
},
|
|
3446
|
+
}),
|
|
3335
3447
|
op({
|
|
3336
3448
|
id: "email.send",
|
|
3337
3449
|
group: "email",
|
|
@@ -4825,7 +4937,7 @@ const rawApiOperations = [
|
|
|
4825
4937
|
path: "/tools/connections",
|
|
4826
4938
|
requestSchema: anyObject,
|
|
4827
4939
|
responseSchema: anyResponse,
|
|
4828
|
-
backend:
|
|
4940
|
+
backend: custom("nativeToolConnect", "bearer"),
|
|
4829
4941
|
}),
|
|
4830
4942
|
op({
|
|
4831
4943
|
id: "tool.search",
|
|
@@ -4836,7 +4948,7 @@ const rawApiOperations = [
|
|
|
4836
4948
|
path: "/tools/search",
|
|
4837
4949
|
requestSchema: anyObject,
|
|
4838
4950
|
responseSchema: anyResponse,
|
|
4839
|
-
backend:
|
|
4951
|
+
backend: custom("nativeToolSearch", "bearer"),
|
|
4840
4952
|
}),
|
|
4841
4953
|
op({
|
|
4842
4954
|
id: "tool.run",
|
|
@@ -4852,7 +4964,7 @@ const rawApiOperations = [
|
|
|
4852
4964
|
path: "/tools/run",
|
|
4853
4965
|
requestSchema: anyObject,
|
|
4854
4966
|
responseSchema: anyResponse,
|
|
4855
|
-
backend:
|
|
4967
|
+
backend: custom("nativeToolRun", "bearer"),
|
|
4856
4968
|
}),
|
|
4857
4969
|
op({
|
|
4858
4970
|
id: "tool.disconnect",
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type EnrichedCompanyUpsertLike,
|
|
3
|
+
type EnrichedPersonUpsertLike,
|
|
4
|
+
shapeCompanyToApolloEnvelope,
|
|
5
|
+
shapePersonToApolloEnvelope,
|
|
6
|
+
} from "./enrichment-shapes";
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
ApolloCompanyEnvelope,
|
|
10
|
+
ApolloPersonEnvelope,
|
|
11
|
+
} from "./enrichment-shapes";
|
|
12
|
+
|
|
1
13
|
import { extractDomain } from "./crm-enrichment";
|
|
2
14
|
|
|
3
15
|
export type FetchLike = (
|
|
@@ -315,188 +327,6 @@ function mapRequiredFieldsToEnrichFields(rf?: string[]): EnrichField[] {
|
|
|
315
327
|
// Apollo-shape envelope (preserves crm-enrichment catalog extraction paths)
|
|
316
328
|
// ---------------------------------------------------------------------------
|
|
317
329
|
|
|
318
|
-
export type ApolloPersonEnvelope = {
|
|
319
|
-
person: {
|
|
320
|
-
search_match?: {
|
|
321
|
-
derivedFields: string[];
|
|
322
|
-
basis: "current_title" | "employment_title";
|
|
323
|
-
};
|
|
324
|
-
name?: string;
|
|
325
|
-
first_name?: string;
|
|
326
|
-
last_name?: string;
|
|
327
|
-
email?: string;
|
|
328
|
-
work_email?: string;
|
|
329
|
-
personal_email?: string;
|
|
330
|
-
photo_url?: string;
|
|
331
|
-
linkedin_url?: string;
|
|
332
|
-
title?: string;
|
|
333
|
-
headline?: string;
|
|
334
|
-
location?: string;
|
|
335
|
-
organization?: {
|
|
336
|
-
name?: string;
|
|
337
|
-
domain?: string;
|
|
338
|
-
website_url?: string;
|
|
339
|
-
};
|
|
340
|
-
organization_name?: string;
|
|
341
|
-
contact: {
|
|
342
|
-
phone_numbers: Array<{
|
|
343
|
-
sanitized_number: string;
|
|
344
|
-
raw_number?: string;
|
|
345
|
-
}>;
|
|
346
|
-
};
|
|
347
|
-
};
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
type EnrichedPersonUpsertLike = {
|
|
351
|
-
avatarUrl?: string;
|
|
352
|
-
searchMatch?: {
|
|
353
|
-
derivedFields: string[];
|
|
354
|
-
basis: "current_title" | "employment_title";
|
|
355
|
-
};
|
|
356
|
-
fullName?: string;
|
|
357
|
-
firstName?: string;
|
|
358
|
-
lastName?: string;
|
|
359
|
-
headline?: string;
|
|
360
|
-
/** Structured title from the person's current role (distinct from headline). */
|
|
361
|
-
currentTitle?: string;
|
|
362
|
-
linkedinID?: string;
|
|
363
|
-
location?: string;
|
|
364
|
-
locationName?: string;
|
|
365
|
-
currentCompanyName?: string;
|
|
366
|
-
currentCompanyWebsite?: string;
|
|
367
|
-
emails?: Array<{
|
|
368
|
-
address?: string;
|
|
369
|
-
normalizedAddress?: string;
|
|
370
|
-
type?: string;
|
|
371
|
-
}>;
|
|
372
|
-
phones?: Array<{ number?: string; normalizedNumber?: string }>;
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
function shapePersonToApolloEnvelope(
|
|
376
|
-
u: EnrichedPersonUpsertLike,
|
|
377
|
-
): ApolloPersonEnvelope {
|
|
378
|
-
const workEmail = u.emails?.find((e) => e.type === "work")?.address;
|
|
379
|
-
const personalEmail = u.emails?.find((e) => e.type === "personal")?.address;
|
|
380
|
-
const anyEmail = u.emails?.[0]?.address;
|
|
381
|
-
const companyName = u.currentCompanyName;
|
|
382
|
-
const companyWebsite = u.currentCompanyWebsite;
|
|
383
|
-
return {
|
|
384
|
-
person: {
|
|
385
|
-
...(u.searchMatch ? { search_match: u.searchMatch } : {}),
|
|
386
|
-
name: u.fullName,
|
|
387
|
-
first_name: u.firstName,
|
|
388
|
-
last_name: u.lastName,
|
|
389
|
-
email: workEmail ?? anyEmail,
|
|
390
|
-
work_email: workEmail,
|
|
391
|
-
personal_email: personalEmail,
|
|
392
|
-
photo_url: u.avatarUrl,
|
|
393
|
-
linkedin_url: u.linkedinID
|
|
394
|
-
? `https://www.linkedin.com/in/${u.linkedinID}`
|
|
395
|
-
: undefined,
|
|
396
|
-
title: u.currentTitle,
|
|
397
|
-
headline: u.headline,
|
|
398
|
-
location: u.location ?? u.locationName,
|
|
399
|
-
organization:
|
|
400
|
-
companyName || companyWebsite
|
|
401
|
-
? {
|
|
402
|
-
name: companyName,
|
|
403
|
-
domain: companyWebsite,
|
|
404
|
-
website_url: companyWebsite,
|
|
405
|
-
}
|
|
406
|
-
: undefined,
|
|
407
|
-
organization_name: companyName,
|
|
408
|
-
contact: {
|
|
409
|
-
phone_numbers: (u.phones ?? []).map((p) => ({
|
|
410
|
-
sanitized_number: p.normalizedNumber ?? p.number ?? "",
|
|
411
|
-
raw_number: p.number,
|
|
412
|
-
})),
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// ---------------------------------------------------------------------------
|
|
419
|
-
// Organization-shape envelope (preserves COMPANY_ENRICHMENT_COLUMNS paths)
|
|
420
|
-
// ---------------------------------------------------------------------------
|
|
421
|
-
|
|
422
|
-
export type ApolloCompanyEnvelope = {
|
|
423
|
-
organization: {
|
|
424
|
-
name?: string;
|
|
425
|
-
domain?: string;
|
|
426
|
-
website_url?: string;
|
|
427
|
-
industry?: string;
|
|
428
|
-
industry_list?: string[];
|
|
429
|
-
specialties?: string[];
|
|
430
|
-
linkedin_url?: string;
|
|
431
|
-
founded_year?: number;
|
|
432
|
-
headcount?: number;
|
|
433
|
-
headcount_range?: string;
|
|
434
|
-
total_funding?: number;
|
|
435
|
-
description?: string;
|
|
436
|
-
hq_city?: string;
|
|
437
|
-
hq_country?: string;
|
|
438
|
-
hq_country_code?: string;
|
|
439
|
-
hq_location?: string;
|
|
440
|
-
};
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
type EnrichedCompanyUpsertLike = {
|
|
444
|
-
name?: string;
|
|
445
|
-
website?: string;
|
|
446
|
-
industry?: string;
|
|
447
|
-
industryList?: string[];
|
|
448
|
-
specialties?: string[];
|
|
449
|
-
linkedinUrl?: string;
|
|
450
|
-
founded?: number;
|
|
451
|
-
headcount?: number;
|
|
452
|
-
headcountRange?: string;
|
|
453
|
-
totalFunding?: number;
|
|
454
|
-
description?: string;
|
|
455
|
-
hqAddress?: {
|
|
456
|
-
line1?: string;
|
|
457
|
-
line2?: string;
|
|
458
|
-
city?: string;
|
|
459
|
-
region?: string;
|
|
460
|
-
country?: string;
|
|
461
|
-
countryCode?: string;
|
|
462
|
-
};
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
function shapeCompanyToApolloEnvelope(
|
|
466
|
-
c: EnrichedCompanyUpsertLike,
|
|
467
|
-
): ApolloCompanyEnvelope {
|
|
468
|
-
const hq = c.hqAddress;
|
|
469
|
-
const city = hq?.city;
|
|
470
|
-
const country = hq?.country ?? hq?.countryCode;
|
|
471
|
-
const hqLocationParts = [city ?? hq?.line1, hq?.region, country].filter(
|
|
472
|
-
(v): v is string => typeof v === "string" && v.length > 0,
|
|
473
|
-
);
|
|
474
|
-
return {
|
|
475
|
-
organization: {
|
|
476
|
-
name: c.name,
|
|
477
|
-
domain: c.website,
|
|
478
|
-
website_url: c.website,
|
|
479
|
-
industry: c.industry,
|
|
480
|
-
industry_list: c.industryList,
|
|
481
|
-
specialties: c.specialties,
|
|
482
|
-
linkedin_url: c.linkedinUrl,
|
|
483
|
-
founded_year: c.founded,
|
|
484
|
-
headcount: c.headcount,
|
|
485
|
-
headcount_range: c.headcountRange,
|
|
486
|
-
total_funding: c.totalFunding,
|
|
487
|
-
description: c.description,
|
|
488
|
-
hq_city: city,
|
|
489
|
-
hq_country: hq?.country,
|
|
490
|
-
hq_country_code: hq?.countryCode,
|
|
491
|
-
hq_location:
|
|
492
|
-
hq?.line2?.trim() ||
|
|
493
|
-
(hqLocationParts.length > 0
|
|
494
|
-
? [...new Set(hqLocationParts)].join(", ")
|
|
495
|
-
: undefined),
|
|
496
|
-
},
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
|
|
500
330
|
// ---------------------------------------------------------------------------
|
|
501
331
|
// enrichPerson — calls POST /v1/enrichment/person/contact with block-and-poll
|
|
502
332
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/** Pure shared projection of gateway profiles into the existing entity-card contract. */
|
|
2
|
+
export type ApolloPersonEnvelope = {
|
|
3
|
+
person: {
|
|
4
|
+
search_match?: {
|
|
5
|
+
derivedFields: string[];
|
|
6
|
+
basis: "current_title" | "employment_title";
|
|
7
|
+
};
|
|
8
|
+
name?: string;
|
|
9
|
+
first_name?: string;
|
|
10
|
+
last_name?: string;
|
|
11
|
+
email?: string;
|
|
12
|
+
work_email?: string;
|
|
13
|
+
personal_email?: string;
|
|
14
|
+
photo_url?: string;
|
|
15
|
+
linkedin_url?: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
headline?: string;
|
|
18
|
+
location?: string;
|
|
19
|
+
organization?: {
|
|
20
|
+
name?: string;
|
|
21
|
+
domain?: string;
|
|
22
|
+
website_url?: string;
|
|
23
|
+
};
|
|
24
|
+
organization_name?: string;
|
|
25
|
+
contact: {
|
|
26
|
+
phone_numbers: Array<{
|
|
27
|
+
sanitized_number: string;
|
|
28
|
+
raw_number?: string;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type EnrichedPersonUpsertLike = {
|
|
35
|
+
avatarUrl?: string;
|
|
36
|
+
searchMatch?: {
|
|
37
|
+
derivedFields: string[];
|
|
38
|
+
basis: "current_title" | "employment_title";
|
|
39
|
+
};
|
|
40
|
+
fullName?: string;
|
|
41
|
+
firstName?: string;
|
|
42
|
+
lastName?: string;
|
|
43
|
+
headline?: string;
|
|
44
|
+
/** Structured title from the person's current role (distinct from headline). */
|
|
45
|
+
currentTitle?: string;
|
|
46
|
+
linkedinID?: string;
|
|
47
|
+
location?: string;
|
|
48
|
+
locationName?: string;
|
|
49
|
+
currentCompanyName?: string;
|
|
50
|
+
currentCompanyWebsite?: string;
|
|
51
|
+
emails?: Array<{
|
|
52
|
+
address?: string;
|
|
53
|
+
normalizedAddress?: string;
|
|
54
|
+
type?: string;
|
|
55
|
+
}>;
|
|
56
|
+
phones?: Array<{ number?: string; normalizedNumber?: string }>;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export function shapePersonToApolloEnvelope(
|
|
60
|
+
u: EnrichedPersonUpsertLike,
|
|
61
|
+
): ApolloPersonEnvelope {
|
|
62
|
+
const workEmail = u.emails?.find((e) => e.type === "work")?.address;
|
|
63
|
+
const personalEmail = u.emails?.find((e) => e.type === "personal")?.address;
|
|
64
|
+
const anyEmail = u.emails?.[0]?.address;
|
|
65
|
+
const companyName = u.currentCompanyName;
|
|
66
|
+
const companyWebsite = u.currentCompanyWebsite;
|
|
67
|
+
return {
|
|
68
|
+
person: {
|
|
69
|
+
...(u.searchMatch ? { search_match: u.searchMatch } : {}),
|
|
70
|
+
name: u.fullName,
|
|
71
|
+
first_name: u.firstName,
|
|
72
|
+
last_name: u.lastName,
|
|
73
|
+
email: workEmail ?? anyEmail,
|
|
74
|
+
work_email: workEmail,
|
|
75
|
+
personal_email: personalEmail,
|
|
76
|
+
photo_url: u.avatarUrl,
|
|
77
|
+
linkedin_url: u.linkedinID
|
|
78
|
+
? `https://www.linkedin.com/in/${u.linkedinID}`
|
|
79
|
+
: undefined,
|
|
80
|
+
title: u.currentTitle,
|
|
81
|
+
headline: u.headline,
|
|
82
|
+
location: u.location ?? u.locationName,
|
|
83
|
+
organization:
|
|
84
|
+
companyName || companyWebsite
|
|
85
|
+
? {
|
|
86
|
+
name: companyName,
|
|
87
|
+
domain: companyWebsite,
|
|
88
|
+
website_url: companyWebsite,
|
|
89
|
+
}
|
|
90
|
+
: undefined,
|
|
91
|
+
organization_name: companyName,
|
|
92
|
+
contact: {
|
|
93
|
+
phone_numbers: (u.phones ?? []).map((p) => ({
|
|
94
|
+
sanitized_number: p.normalizedNumber ?? p.number ?? "",
|
|
95
|
+
raw_number: p.number,
|
|
96
|
+
})),
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Organization-shape envelope (preserves COMPANY_ENRICHMENT_COLUMNS paths)
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
export type ApolloCompanyEnvelope = {
|
|
107
|
+
organization: {
|
|
108
|
+
name?: string;
|
|
109
|
+
domain?: string;
|
|
110
|
+
website_url?: string;
|
|
111
|
+
industry?: string;
|
|
112
|
+
industry_list?: string[];
|
|
113
|
+
specialties?: string[];
|
|
114
|
+
linkedin_url?: string;
|
|
115
|
+
founded_year?: number;
|
|
116
|
+
headcount?: number;
|
|
117
|
+
headcount_range?: string;
|
|
118
|
+
total_funding?: number;
|
|
119
|
+
description?: string;
|
|
120
|
+
hq_city?: string;
|
|
121
|
+
hq_country?: string;
|
|
122
|
+
hq_country_code?: string;
|
|
123
|
+
hq_location?: string;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export type EnrichedCompanyUpsertLike = {
|
|
128
|
+
name?: string;
|
|
129
|
+
website?: string;
|
|
130
|
+
industry?: string;
|
|
131
|
+
industryList?: string[];
|
|
132
|
+
specialties?: string[];
|
|
133
|
+
linkedinUrl?: string;
|
|
134
|
+
founded?: number;
|
|
135
|
+
headcount?: number;
|
|
136
|
+
headcountRange?: string;
|
|
137
|
+
totalFunding?: number;
|
|
138
|
+
description?: string;
|
|
139
|
+
hqAddress?: {
|
|
140
|
+
line1?: string;
|
|
141
|
+
line2?: string;
|
|
142
|
+
city?: string;
|
|
143
|
+
region?: string;
|
|
144
|
+
country?: string;
|
|
145
|
+
countryCode?: string;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export function shapeCompanyToApolloEnvelope(
|
|
150
|
+
c: EnrichedCompanyUpsertLike,
|
|
151
|
+
): ApolloCompanyEnvelope {
|
|
152
|
+
const hq = c.hqAddress;
|
|
153
|
+
const city = hq?.city;
|
|
154
|
+
const country = hq?.country ?? hq?.countryCode;
|
|
155
|
+
const hqLocationParts = [city ?? hq?.line1, hq?.region, country].filter(
|
|
156
|
+
(v): v is string => typeof v === "string" && v.length > 0,
|
|
157
|
+
);
|
|
158
|
+
return {
|
|
159
|
+
organization: {
|
|
160
|
+
name: c.name,
|
|
161
|
+
domain: c.website,
|
|
162
|
+
website_url: c.website,
|
|
163
|
+
industry: c.industry,
|
|
164
|
+
industry_list: c.industryList,
|
|
165
|
+
specialties: c.specialties,
|
|
166
|
+
linkedin_url: c.linkedinUrl,
|
|
167
|
+
founded_year: c.founded,
|
|
168
|
+
headcount: c.headcount,
|
|
169
|
+
headcount_range: c.headcountRange,
|
|
170
|
+
total_funding: c.totalFunding,
|
|
171
|
+
description: c.description,
|
|
172
|
+
hq_city: city,
|
|
173
|
+
hq_country: hq?.country,
|
|
174
|
+
hq_country_code: hq?.countryCode,
|
|
175
|
+
hq_location:
|
|
176
|
+
hq?.line2?.trim() ||
|
|
177
|
+
(hqLocationParts.length > 0
|
|
178
|
+
? [...new Set(hqLocationParts)].join(", ")
|
|
179
|
+
: undefined),
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|