lumnisai 0.5.22 → 0.5.24

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.cjs CHANGED
@@ -1083,6 +1083,31 @@ class EmailResource {
1083
1083
  { params: { user_id: userId } }
1084
1084
  );
1085
1085
  }
1086
+ // ==================== BYO Inboxes ====================
1087
+ /**
1088
+ * Connect a customer's own email inbox (Gmail/Outlook/IMAP) via Unipile.
1089
+ *
1090
+ * One call = one inbox. Returns a hosted-auth redirect URL; the user authes
1091
+ * there and the connect webhook creates the `ready` mailbox. Call once per
1092
+ * inbox to add multiple mailboxes.
1093
+ */
1094
+ async connectInbox(request) {
1095
+ return this.http.post("/email/inboxes/connect", request);
1096
+ }
1097
+ /**
1098
+ * Update a single mailbox's send settings (per-mailbox daily cap, pause).
1099
+ *
1100
+ * PATCH semantics — only provided fields change. The per-mailbox cap is the
1101
+ * primary lever for BYO inboxes, which skip the InboxKit warmup ramp.
1102
+ * Requires admin role on the org.
1103
+ */
1104
+ async updateMailbox(orgId, mailboxId, userId, update) {
1105
+ return this.http.patch(
1106
+ `/email/organizations/${encodeURIComponent(orgId)}/mailboxes/${encodeURIComponent(mailboxId)}`,
1107
+ update,
1108
+ { params: { user_id: userId } }
1109
+ );
1110
+ }
1086
1111
  // ==================== Teardown ====================
1087
1112
  /**
1088
1113
  * Teardown an email organization's infrastructure.
@@ -2845,6 +2870,71 @@ class ModelPreferencesResource {
2845
2870
  }
2846
2871
  }
2847
2872
 
2873
+ class OutreachResource {
2874
+ constructor(http) {
2875
+ this.http = http;
2876
+ }
2877
+ /**
2878
+ * List people at a funnel stage (connected/messaged/replied/meeting_booked),
2879
+ * or `stage='all'` for one row per person at their furthest stage.
2880
+ *
2881
+ * Pass `stats: true` to also get the per-channel funnel counts + conversion
2882
+ * ratios for the same scope (`userId`/`source`/`campaignId`) alongside the
2883
+ * people list. Pass `campaignId` to restrict to specific campaigns (this
2884
+ * excludes sequences).
2885
+ *
2886
+ * @example
2887
+ * ```typescript
2888
+ * const result = await client.outreach.listConnections({
2889
+ * userId: 'user@example.com',
2890
+ * stage: 'replied',
2891
+ * stats: true,
2892
+ * })
2893
+ * console.log(result.total, result.stats?.byChannel.linkedin.ratios.replyRate)
2894
+ * ```
2895
+ */
2896
+ async listConnections(params) {
2897
+ const query = new URLSearchParams();
2898
+ query.append("user_id", params.userId);
2899
+ if (params.stage !== void 0)
2900
+ query.append("stage", params.stage);
2901
+ if (params.channel !== void 0)
2902
+ query.append("channel", params.channel);
2903
+ if (params.source !== void 0)
2904
+ query.append("source", params.source);
2905
+ if (params.campaignId)
2906
+ params.campaignId.forEach((id) => query.append("campaign_id", id));
2907
+ if (params.since !== void 0)
2908
+ query.append("since", params.since);
2909
+ if (params.stats !== void 0)
2910
+ query.append("stats", String(params.stats));
2911
+ if (params.limit !== void 0)
2912
+ query.append("limit", String(params.limit));
2913
+ if (params.offset !== void 0)
2914
+ query.append("offset", String(params.offset));
2915
+ return this.http.get(`/outreach?${query.toString()}`);
2916
+ }
2917
+ /**
2918
+ * Alias for `stage='connected'` — people who accepted a Lumnis-sent
2919
+ * connection request.
2920
+ */
2921
+ async listAcceptedConnections(params) {
2922
+ const query = new URLSearchParams();
2923
+ query.append("user_id", params.userId);
2924
+ if (params.source !== void 0)
2925
+ query.append("source", params.source);
2926
+ if (params.campaignId)
2927
+ params.campaignId.forEach((id) => query.append("campaign_id", id));
2928
+ if (params.since !== void 0)
2929
+ query.append("since", params.since);
2930
+ if (params.limit !== void 0)
2931
+ query.append("limit", String(params.limit));
2932
+ if (params.offset !== void 0)
2933
+ query.append("offset", String(params.offset));
2934
+ return this.http.get(`/outreach/accepted?${query.toString()}`);
2935
+ }
2936
+ }
2937
+
2848
2938
  var PeopleDataSource = /* @__PURE__ */ ((PeopleDataSource2) => {
2849
2939
  PeopleDataSource2["PDL"] = "PDL";
2850
2940
  PeopleDataSource2["CORESIGNAL"] = "CORESIGNAL";
@@ -3128,6 +3218,59 @@ class ResponsesResource {
3128
3218
  throw new ValidationError("maxCommentsPerPost must be between 1 and 100");
3129
3219
  }
3130
3220
  }
3221
+ _validateCompetitorRepEngagementParams(params) {
3222
+ const company = this._getParamValue(params, "company", "company");
3223
+ const competitors = this._getParamValue(params, "competitors", "competitors");
3224
+ const engagementTypes = this._getParamValue(
3225
+ params,
3226
+ "engagementTypes",
3227
+ "engagement_types"
3228
+ );
3229
+ const hasCompany = typeof company === "string" && company.trim().length > 0;
3230
+ const hasCompetitors = Array.isArray(competitors) && competitors.length > 0;
3231
+ if (hasCompany === hasCompetitors) {
3232
+ throw new ValidationError(
3233
+ "Provide exactly one of `company` or `competitors` for competitor_rep_engagement."
3234
+ );
3235
+ }
3236
+ if (engagementTypes !== void 0) {
3237
+ if (!Array.isArray(engagementTypes) || engagementTypes.length === 0) {
3238
+ throw new ValidationError("engagementTypes must contain at least one value");
3239
+ }
3240
+ const validTypes = ["reactor", "commenter"];
3241
+ for (const type of engagementTypes) {
3242
+ if (!validTypes.includes(type)) {
3243
+ throw new ValidationError(
3244
+ `Invalid engagementTypes value: ${String(type)}. Expected 'reactor' and/or 'commenter'.`
3245
+ );
3246
+ }
3247
+ }
3248
+ }
3249
+ const limit = this._getParamValue(params, "limit", "limit");
3250
+ if (limit !== void 0 && (limit < 1 || limit > 1e3)) {
3251
+ throw new ValidationError("limit must be between 1 and 1000 for competitor_rep_engagement");
3252
+ }
3253
+ const maxCompetitors = this._getParamValue(params, "maxCompetitors", "max_competitors");
3254
+ if (maxCompetitors !== void 0 && (maxCompetitors < 1 || maxCompetitors > 50)) {
3255
+ throw new ValidationError("maxCompetitors must be between 1 and 50");
3256
+ }
3257
+ const maxRepsPerCompetitor = this._getParamValue(
3258
+ params,
3259
+ "maxRepsPerCompetitor",
3260
+ "max_reps_per_competitor"
3261
+ );
3262
+ if (maxRepsPerCompetitor !== void 0 && (maxRepsPerCompetitor < 1 || maxRepsPerCompetitor > 100)) {
3263
+ throw new ValidationError("maxRepsPerCompetitor must be between 1 and 100");
3264
+ }
3265
+ const maxEngagementsPerRep = this._getParamValue(
3266
+ params,
3267
+ "maxEngagementsPerRep",
3268
+ "max_engagements_per_rep"
3269
+ );
3270
+ if (maxEngagementsPerRep !== void 0 && (maxEngagementsPerRep < 1 || maxEngagementsPerRep > 1e3)) {
3271
+ throw new ValidationError("maxEngagementsPerRep must be between 1 and 1000");
3272
+ }
3273
+ }
3131
3274
  _validateCriteriaParams(params, specializedAgent) {
3132
3275
  if (!params)
3133
3276
  return;
@@ -3228,6 +3371,8 @@ class ResponsesResource {
3228
3371
  }
3229
3372
  if (specializedAgent === "competitor_post_engagement")
3230
3373
  this._validateCompetitorPostEngagementParams(rawParams);
3374
+ if (specializedAgent === "competitor_rep_engagement")
3375
+ this._validateCompetitorRepEngagementParams(rawParams);
3231
3376
  }
3232
3377
  _validateFileReference(uri) {
3233
3378
  if (uri.startsWith("artifact_"))
@@ -3563,6 +3708,70 @@ class ResponsesResource {
3563
3708
  request.specializedAgentParams = params;
3564
3709
  return this.create(request);
3565
3710
  }
3711
+ /**
3712
+ * Find a competitor's sales reps and surface the AUTHORS of the LinkedIn posts
3713
+ * those reps engage with — i.e. the prospects the competitor is actively
3714
+ * selling to. The INVERSE of {@link competitorPostEngagement}.
3715
+ *
3716
+ * **Discovery mode** — pass `company`: ReAct discovers competitors, then crawls
3717
+ * each one's reps and harvests their outgoing engagement.
3718
+ *
3719
+ * **Explicit mode** — pass `competitors`: skips discovery, uses your list.
3720
+ *
3721
+ * Requires `FIBER_API_KEY` + `CRUSTDATA_API_KEY`.
3722
+ *
3723
+ * @param query - Persona prompt for the prospect-authors (e.g. "VP Eng at AI-native startups…")
3724
+ * @param options - Exactly one of `company` or `competitors` is required
3725
+ * @returns Response; poll with `get()` then read `structuredResponse` as
3726
+ * {@link CompetitorRepEngagementOutput}. See `src/types/competitor-rep-engagement.ts`
3727
+ * for the full agent reference (pipeline, API keys, engagementData shape).
3728
+ */
3729
+ async competitorRepEngagement(query, options) {
3730
+ const hasCompany = typeof options.company === "string" && options.company.trim().length > 0;
3731
+ const hasCompetitors = Array.isArray(options.competitors) && options.competitors.length > 0;
3732
+ if (hasCompany === hasCompetitors) {
3733
+ throw new ValidationError(
3734
+ "Provide exactly one of `company` or `competitors` for competitorRepEngagement."
3735
+ );
3736
+ }
3737
+ const request = {
3738
+ messages: [{ role: "user", content: query }],
3739
+ specializedAgent: "competitor_rep_engagement"
3740
+ };
3741
+ const params = {};
3742
+ if (options.company)
3743
+ params.company = options.company;
3744
+ if (options.competitors)
3745
+ params.competitors = options.competitors;
3746
+ if (options.companyContext)
3747
+ params.companyContext = options.companyContext;
3748
+ if (options.companyExamples)
3749
+ params.companyExamples = options.companyExamples;
3750
+ if (options.limit !== void 0)
3751
+ params.limit = options.limit;
3752
+ if (options.postsDateRange)
3753
+ params.postsDateRange = options.postsDateRange;
3754
+ if (options.engagementTypes)
3755
+ params.engagementTypes = options.engagementTypes;
3756
+ if (options.repTitles)
3757
+ params.repTitles = options.repTitles;
3758
+ if (options.maxRepsPerCompetitor !== void 0)
3759
+ params.maxRepsPerCompetitor = options.maxRepsPerCompetitor;
3760
+ if (options.maxEngagementsPerRep !== void 0)
3761
+ params.maxEngagementsPerRep = options.maxEngagementsPerRep;
3762
+ if (options.restrictEngagementToTenure !== void 0)
3763
+ params.restrictEngagementToTenure = options.restrictEngagementToTenure;
3764
+ if (options.excludeCompetitorEmployees !== void 0)
3765
+ params.excludeCompetitorEmployees = options.excludeCompetitorEmployees;
3766
+ if (options.expandExclusionViaDiscovery !== void 0)
3767
+ params.expandExclusionViaDiscovery = options.expandExclusionViaDiscovery;
3768
+ if (options.maxCompetitors !== void 0)
3769
+ params.maxCompetitors = options.maxCompetitors;
3770
+ if (options.thoroughEnrichment !== void 0)
3771
+ params.thoroughEnrichment = options.thoroughEnrichment;
3772
+ request.specializedAgentParams = params;
3773
+ return this.create(request);
3774
+ }
3566
3775
  }
3567
3776
 
3568
3777
  class SequencesResource {
@@ -4501,6 +4710,7 @@ class LumnisClient {
4501
4710
  enrichment;
4502
4711
  email;
4503
4712
  crm;
4713
+ outreach;
4504
4714
  _scopedUserId;
4505
4715
  _defaultScope;
4506
4716
  constructor(options = {}) {
@@ -4539,6 +4749,7 @@ class LumnisClient {
4539
4749
  this.enrichment = new EnrichmentResource(this.http);
4540
4750
  this.email = new EmailResource(this.http);
4541
4751
  this.crm = new CrmResource(this.http);
4752
+ this.outreach = new OutreachResource(this.http);
4542
4753
  }
4543
4754
  forUser(userId) {
4544
4755
  return new LumnisClient({