@signaliz/sdk 1.0.53 → 1.0.55

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @signaliz/sdk
2
2
 
3
- Typed JavaScript/TypeScript access to the four Signaliz products.
3
+ Typed JavaScript/TypeScript access to all five core products in Signaliz.
4
4
 
5
5
  ```bash
6
6
  npm install @signaliz/sdk
@@ -12,6 +12,7 @@ Production REST endpoints:
12
12
  - `https://api.signaliz.com/functions/v1/api/v1/verify-email`
13
13
  - `https://api.signaliz.com/functions/v1/api/v1/company-signals`
14
14
  - `https://api.signaliz.com/functions/v1/api/v1/signal-to-copy`
15
+ - `https://api.signaliz.com/functions/v1/api/v1/signals`
15
16
 
16
17
  ```ts
17
18
  import { Signaliz } from '@signaliz/sdk';
@@ -59,6 +60,19 @@ const signals = await signaliz.enrichCompanySignals({
59
60
  console.log(signals.signals[0].evidencePublishedDate);
60
61
  console.log(signals.signals[0].signalFeedSource, signals.signals[0].derived);
61
62
 
63
+ // Query-first discovery returns distinct companies with dated source evidence.
64
+ // The first response is usually queued; resume only the returned run ID.
65
+ const signalDiscovery = await signaliz.discoverSignals({
66
+ query: 'companies that just got funded',
67
+ limit: 100,
68
+ sources: ['web', 'news'],
69
+ });
70
+ const completedDiscovery = signalDiscovery.signalSearchRunId
71
+ ? await signaliz.discoverSignals({ signalSearchRunId: signalDiscovery.signalSearchRunId })
72
+ : signalDiscovery;
73
+ console.log(completedDiscovery.signals[0]?.company.domain);
74
+ console.log(completedDiscovery.costGuardrail?.costPerQualifiedSignalUsd);
75
+
62
76
  const copy = await signaliz.signalToCopy({
63
77
  companyDomain: 'example.com',
64
78
  personName: 'Jane Doe',
@@ -74,7 +88,7 @@ const copy = await signaliz.signalToCopy({
74
88
  // methods return complete data or throw a terminal error in this same call.
75
89
  ```
76
90
 
77
- All four products support bounded batch execution over the same REST endpoints.
91
+ The four row-oriented products support bounded batch execution over the same REST endpoints.
78
92
  Results stay in input order, failures are isolated per item, and concurrency is
79
93
  limited to `1-50` (default `10`):
80
94
 
@@ -100,7 +114,7 @@ For an ambiguous single request or batch submission failure, retry with the
100
114
  same `idempotencyKey` to recover the original request or durable job without duplicate
101
115
  work.
102
116
 
103
- Each batch accepts up to 5,000 items. For all four core products, batches larger
117
+ Each batch accepts up to 5,000 items. For the four row-oriented core products, batches larger
104
118
  than 25 use one recoverable REST job; the SDK waits for completion and retrieves
105
119
  every result page before returning, so callers never receive queued work or
106
120
  polling instructions. Find Email, Verify Email, and Signal to Copy use 500-row
@@ -117,6 +131,16 @@ explicitly requests `skipCache` or `enableDeepSearch`, the SDK preserves that
117
131
  fresh-research behavior by using synchronous client-side chunks of at most 25.
118
132
  Signal to Copy also shares company research across copy recipients.
119
133
 
134
+ Signals Everything is query-first rather than a row batch. It defaults to 100
135
+ distinct companies and supports up to 1,000. Every returned signal contains a
136
+ company name, company domain, dated evidence, and a source URL. The typed
137
+ `costGuardrail` reports both projected and observed source acquisition cost;
138
+ Signaliz returns signals only when cost stays strictly below $0.01 per qualified
139
+ company. A request is a ceiling, not a promise: it can return fewer results
140
+ when public evidence cannot verify both a date and company identity. It is
141
+ included on Team and Agency plans and can be resumed with
142
+ `signalSearchRunId` without duplicate source acquisition.
143
+
120
144
  Company Signal Enrichment defaults `online` and `enableDeepSearch` to `true`
121
145
  unless the caller explicitly disables them. Its `searchMode` defaults to
122
146
  `balanced`; use `fast` for the primary low-latency search lane only or
@@ -468,6 +468,14 @@ var Signaliz = class {
468
468
  assertTerminalSignalResponse(data, "Company Signals");
469
469
  return normalizeCompanySignalResult(params, data);
470
470
  }
471
+ async discoverSignals(params) {
472
+ validateSignalDiscoveryParams(params);
473
+ const data = await this.client.post(
474
+ "api/v1/signals",
475
+ signalDiscoveryRequestBody(params)
476
+ );
477
+ return normalizeSignalDiscoveryResult(params, data);
478
+ }
471
479
  async enrichCompanies(companies, options) {
472
480
  validateBatchSize(companies);
473
481
  companies.forEach((params) => validateCoreProductMaxWaitMs(params.maxWaitMs));
@@ -1020,6 +1028,145 @@ function normalizeCompanySignalResult(params, data) {
1020
1028
  raw: data
1021
1029
  };
1022
1030
  }
1031
+ var SIGNAL_DISCOVERY_SOURCES = /* @__PURE__ */ new Set(["web", "news"]);
1032
+ var SIGNAL_DISCOVERY_STATUSES = /* @__PURE__ */ new Set([
1033
+ "planned",
1034
+ "queued",
1035
+ "processing",
1036
+ "completed",
1037
+ "completed_with_warnings",
1038
+ "failed"
1039
+ ]);
1040
+ function validateSignalDiscoveryParams(params) {
1041
+ const runId = typeof params.signalSearchRunId === "string" ? params.signalSearchRunId.trim() : "";
1042
+ const query = typeof params.query === "string" ? params.query.trim() : "";
1043
+ if (!runId && !query) {
1044
+ throw new TypeError("Signals Everything requires query or signalSearchRunId");
1045
+ }
1046
+ if (query && (query.length < 2 || query.length > 2e3)) {
1047
+ throw new RangeError("query must contain between 2 and 2000 characters");
1048
+ }
1049
+ if (params.limit !== void 0 && (!Number.isInteger(params.limit) || params.limit < 1 || params.limit > 1e3)) {
1050
+ throw new RangeError("limit must be an integer between 1 and 1000");
1051
+ }
1052
+ if (params.lookbackDays !== void 0 && (!Number.isInteger(params.lookbackDays) || params.lookbackDays < 1 || params.lookbackDays > 365)) {
1053
+ throw new RangeError("lookbackDays must be an integer between 1 and 365");
1054
+ }
1055
+ if (params.sources !== void 0 && (!Array.isArray(params.sources) || params.sources.length < 1 || params.sources.length > 2 || params.sources.some((source) => !SIGNAL_DISCOVERY_SOURCES.has(source)))) {
1056
+ throw new TypeError("sources must contain only web or news");
1057
+ }
1058
+ }
1059
+ function signalDiscoveryRequestBody(params) {
1060
+ const runId = typeof params.signalSearchRunId === "string" ? params.signalSearchRunId.trim() : "";
1061
+ if (runId) {
1062
+ return compact({
1063
+ signal_search_run_id: runId,
1064
+ // An explicit limit expands or narrows the retained qualified cohort;
1065
+ // omitting it preserves the original preview size.
1066
+ limit: params.limit,
1067
+ dry_run: params.dryRun,
1068
+ idempotency_key: params.idempotencyKey
1069
+ });
1070
+ }
1071
+ return compact({
1072
+ query: params.query?.trim(),
1073
+ limit: params.limit ?? 100,
1074
+ sources: params.sources,
1075
+ lookback_days: params.lookbackDays,
1076
+ dry_run: params.dryRun,
1077
+ idempotency_key: params.idempotencyKey
1078
+ });
1079
+ }
1080
+ function normalizeSignalDiscoveryResult(params, data) {
1081
+ const rawSignals = Array.isArray(data.signals) ? data.signals : [];
1082
+ const rawStatus = String(data.status || "").toLowerCase();
1083
+ const status = SIGNAL_DISCOVERY_STATUSES.has(rawStatus) ? rawStatus : rawSignals.length > 0 ? "completed" : "failed";
1084
+ const signals = rawSignals.map(normalizeSignalDiscoverySignal);
1085
+ return {
1086
+ success: data.success !== false,
1087
+ status,
1088
+ capability: "signals_everything",
1089
+ signalSearchRunId: String(data.signal_search_run_id ?? params.signalSearchRunId ?? ""),
1090
+ query: String(data.query ?? params.query ?? ""),
1091
+ requestedCount: Number(data.requested_count ?? params.limit ?? 100),
1092
+ nextPollAfterSeconds: typeof data.next_poll_after_seconds === "number" ? data.next_poll_after_seconds : void 0,
1093
+ signals,
1094
+ signalCount: signals.length,
1095
+ availableCompanySignalCount: Number.isFinite(Number(data.available_company_signal_count)) ? Number(data.available_company_signal_count) : void 0,
1096
+ sourceLanes: Array.isArray(data.source_lanes) ? data.source_lanes.filter((lane) => typeof lane === "string") : void 0,
1097
+ evidenceValidation: data.evidence_validation && typeof data.evidence_validation === "object" ? data.evidence_validation : void 0,
1098
+ costGuardrail: normalizeSignalDiscoveryCostGuardrail(data.cost_guardrail),
1099
+ warnings: Array.isArray(data.warnings) ? data.warnings.filter((warning) => typeof warning === "string") : void 0,
1100
+ raw: data
1101
+ };
1102
+ }
1103
+ function normalizeSignalDiscoveryCostGuardrail(value) {
1104
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1105
+ const guardrail = value;
1106
+ const maxCost = Number(guardrail.max_cost_per_qualified_signal_usd);
1107
+ const withinLimit = guardrail.within_limit === true;
1108
+ if (!Number.isFinite(maxCost)) return void 0;
1109
+ const numberOrNullable = (candidate) => {
1110
+ if (candidate === null) return null;
1111
+ const numeric = Number(candidate);
1112
+ return Number.isFinite(numeric) ? numeric : void 0;
1113
+ };
1114
+ const numberOrUndefined = (candidate) => {
1115
+ const numeric = Number(candidate);
1116
+ return Number.isFinite(numeric) ? numeric : void 0;
1117
+ };
1118
+ return {
1119
+ maxCostPerQualifiedSignalUsd: maxCost,
1120
+ projectedSourceCostUsd: numberOrNullable(guardrail.projected_source_cost_usd),
1121
+ maxSourceCostUsd: numberOrNullable(guardrail.max_source_cost_usd),
1122
+ projectedCostPerRequestedCompanySignalUsd: numberOrNullable(
1123
+ guardrail.projected_cost_per_requested_company_signal_usd
1124
+ ),
1125
+ sourceCostUsd: numberOrNullable(guardrail.source_cost_usd),
1126
+ costSource: ["observed", "catalog_bounded", "mixed", "unavailable"].includes(String(guardrail.cost_source)) ? String(guardrail.cost_source) : void 0,
1127
+ qualifiedCompanySignalCount: numberOrUndefined(guardrail.qualified_company_signal_count),
1128
+ returnedCompanySignalCount: numberOrUndefined(guardrail.returned_company_signal_count),
1129
+ availableCompanySignalCount: numberOrUndefined(guardrail.available_company_signal_count),
1130
+ acquisitionCandidateLimit: numberOrUndefined(guardrail.acquisition_candidate_limit),
1131
+ minimumQualifiedCompanySignals: numberOrUndefined(guardrail.minimum_qualified_company_signals),
1132
+ costPerQualifiedSignalUsd: numberOrNullable(guardrail.cost_per_qualified_signal_usd),
1133
+ withinLimit
1134
+ };
1135
+ }
1136
+ function normalizeSignalDiscoverySignal(value) {
1137
+ const signal = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1138
+ const company = signal.company && typeof signal.company === "object" && !Array.isArray(signal.company) ? signal.company : {};
1139
+ const companyName = String(company.name ?? signal.company_name ?? "").trim();
1140
+ const companyDomain = String(company.domain ?? signal.company_domain ?? "").trim();
1141
+ if (!companyName || !companyDomain) {
1142
+ throw new Error("Signals Everything response violated the company attribution contract.");
1143
+ }
1144
+ return {
1145
+ id: signal.id,
1146
+ company: {
1147
+ name: companyName,
1148
+ domain: companyDomain,
1149
+ linkedinUrl: company.linkedin_url ?? signal.company_linkedin_url ?? void 0
1150
+ },
1151
+ title: signal.title ?? "",
1152
+ type: signal.type ?? signal.signal_type ?? "unknown",
1153
+ summary: signal.summary ?? signal.content ?? signal.description ?? "",
1154
+ eventDate: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1155
+ evidence: Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
1156
+ url: String(item?.url ?? ""),
1157
+ publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
1158
+ source: String(item?.source ?? "")
1159
+ })).filter((item) => Boolean(item.url)) : [],
1160
+ content: signal.summary ?? signal.content ?? signal.description ?? "",
1161
+ date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1162
+ detectedAt: signal.event_date ?? signal.detected_at ?? null,
1163
+ sourceUrl: signal.source_url ?? signal.url ?? null,
1164
+ sourceType: signal.source_type ?? null,
1165
+ confidence: signal.confidence ?? signal.confidence_score ?? null,
1166
+ classification: signal.signal_classification ?? signal.classification ?? null,
1167
+ raw: signal
1168
+ };
1169
+ }
1023
1170
  function validateBatchSize(items) {
1024
1171
  if (!Array.isArray(items) || items.length === 0) {
1025
1172
  throw new Error("Signaliz batch requests require at least one item");
package/dist/index.d.mts CHANGED
@@ -219,6 +219,89 @@ interface CompanySignalEnrichmentResult {
219
219
  evidenceScope?: 'selected_signals' | 'all_candidates';
220
220
  raw: Record<string, unknown>;
221
221
  }
222
+ type SignalDiscoverySource = 'web' | 'news';
223
+ type SignalDiscoveryStatus = 'planned' | 'queued' | 'processing' | 'completed' | 'completed_with_warnings' | 'failed';
224
+ interface SignalDiscoveryParams {
225
+ /** Natural-language description of the signals to find. Required for a new search. */
226
+ query?: string;
227
+ /** Number of qualified company signals requested. Defaults to 100; allowed range is 1-1,000. */
228
+ limit?: number;
229
+ /** Restrict discovery to selected source families. */
230
+ sources?: SignalDiscoverySource[];
231
+ /** Maximum signal age in days. Allowed range is 1-365. */
232
+ lookbackDays?: number;
233
+ /** Resume an existing asynchronous discovery run without starting another search. */
234
+ signalSearchRunId?: string;
235
+ /** Stable retry key for recovering the same search after an ambiguous response. */
236
+ idempotencyKey?: string;
237
+ /** Return a no-dispatch plan without provider calls or jobs. */
238
+ dryRun?: boolean;
239
+ }
240
+ interface SignalDiscoverySignal {
241
+ id?: string;
242
+ company: {
243
+ /** Every returned discovery signal is attributed to a distinct company. */
244
+ name: string;
245
+ domain: string;
246
+ linkedinUrl?: string | null;
247
+ };
248
+ title: string;
249
+ type: string;
250
+ summary: string;
251
+ eventDate?: string | null;
252
+ evidence: Array<{
253
+ url: string;
254
+ publishedAt: string;
255
+ source: string;
256
+ }>;
257
+ /** Compatibility alias for summary. */
258
+ content: string;
259
+ /** Compatibility alias for eventDate. */
260
+ date?: string | null;
261
+ detectedAt?: string | null;
262
+ sourceUrl?: string | null;
263
+ sourceType?: string | null;
264
+ confidence?: number | null;
265
+ classification?: Record<string, unknown> | string | null;
266
+ raw: Record<string, unknown>;
267
+ }
268
+ interface SignalDiscoveryCostGuardrail {
269
+ /** Strict ceiling: a qualified company signal must cost less than this amount to return. */
270
+ maxCostPerQualifiedSignalUsd: number;
271
+ projectedSourceCostUsd?: number | null;
272
+ maxSourceCostUsd?: number | null;
273
+ projectedCostPerRequestedCompanySignalUsd?: number | null;
274
+ sourceCostUsd?: number | null;
275
+ costSource?: 'observed' | 'catalog_bounded' | 'mixed' | 'unavailable';
276
+ qualifiedCompanySignalCount?: number;
277
+ returnedCompanySignalCount?: number;
278
+ /** Qualified signals retained on the same search run for later expansion. */
279
+ availableCompanySignalCount?: number;
280
+ /** Raw source candidate ceiling per selected source lane used to form the cohort. */
281
+ acquisitionCandidateLimit?: number;
282
+ /** Minimum qualified companies needed for the source receipt to stay below one cent each. */
283
+ minimumQualifiedCompanySignals?: number;
284
+ costPerQualifiedSignalUsd?: number | null;
285
+ withinLimit: boolean;
286
+ }
287
+ interface SignalDiscoveryResult {
288
+ success: boolean;
289
+ status: SignalDiscoveryStatus;
290
+ capability: 'signals_everything';
291
+ signalSearchRunId: string;
292
+ query: string;
293
+ requestedCount: number;
294
+ nextPollAfterSeconds?: number;
295
+ signals: SignalDiscoverySignal[];
296
+ signalCount: number;
297
+ /** Number of qualified company signals retained on signalSearchRunId. */
298
+ availableCompanySignalCount?: number;
299
+ sourceLanes?: string[];
300
+ evidenceValidation?: Record<string, unknown>;
301
+ costGuardrail?: SignalDiscoveryCostGuardrail;
302
+ warnings?: string[];
303
+ raw: Record<string, unknown>;
304
+ }
222
305
  interface SignalToCopyParams {
223
306
  companyDomain?: string;
224
307
  personName?: string;
@@ -310,6 +393,7 @@ declare class Signaliz {
310
393
  dryRun: true;
311
394
  }): Promise<CoreProductDryRunResult>;
312
395
  enrichCompanySignals(params: CompanySignalEnrichmentParams): Promise<CompanySignalEnrichmentResult>;
396
+ discoverSignals(params: SignalDiscoveryParams): Promise<SignalDiscoveryResult>;
313
397
  enrichCompanies(companies: CompanySignalEnrichmentParams[], options: BatchOptions & {
314
398
  dryRun: true;
315
399
  }): Promise<CoreProductDryRunResult>;
@@ -331,4 +415,4 @@ declare class Signaliz {
331
415
  health(): Promise<PlatformHealth>;
332
416
  }
333
417
 
334
- export { type BatchItemResult, type BatchOptions, type BatchResult, type CompanySignal, type CompanySignalEnrichmentParams, type CompanySignalEnrichmentResult, type ErrorType, type FindEmailParams, type FindEmailResult, type MCPToolInfo, type PlatformHealth, type SignalToCopyParams, type SignalToCopyResult, type SignalToCopyVariation, Signaliz, type SignalizConfig, SignalizError, type SignalizErrorData, type VerifyEmailBatchOptions, type VerifyEmailOptions, type VerifyEmailResult };
418
+ export { type BatchItemResult, type BatchOptions, type BatchResult, type CompanySignal, type CompanySignalEnrichmentParams, type CompanySignalEnrichmentResult, type ErrorType, type FindEmailParams, type FindEmailResult, type MCPToolInfo, type PlatformHealth, type SignalDiscoveryParams, type SignalDiscoveryResult, type SignalDiscoverySignal, type SignalDiscoverySource, type SignalDiscoveryStatus, type SignalToCopyParams, type SignalToCopyResult, type SignalToCopyVariation, Signaliz, type SignalizConfig, SignalizError, type SignalizErrorData, type VerifyEmailBatchOptions, type VerifyEmailOptions, type VerifyEmailResult };
package/dist/index.d.ts CHANGED
@@ -219,6 +219,89 @@ interface CompanySignalEnrichmentResult {
219
219
  evidenceScope?: 'selected_signals' | 'all_candidates';
220
220
  raw: Record<string, unknown>;
221
221
  }
222
+ type SignalDiscoverySource = 'web' | 'news';
223
+ type SignalDiscoveryStatus = 'planned' | 'queued' | 'processing' | 'completed' | 'completed_with_warnings' | 'failed';
224
+ interface SignalDiscoveryParams {
225
+ /** Natural-language description of the signals to find. Required for a new search. */
226
+ query?: string;
227
+ /** Number of qualified company signals requested. Defaults to 100; allowed range is 1-1,000. */
228
+ limit?: number;
229
+ /** Restrict discovery to selected source families. */
230
+ sources?: SignalDiscoverySource[];
231
+ /** Maximum signal age in days. Allowed range is 1-365. */
232
+ lookbackDays?: number;
233
+ /** Resume an existing asynchronous discovery run without starting another search. */
234
+ signalSearchRunId?: string;
235
+ /** Stable retry key for recovering the same search after an ambiguous response. */
236
+ idempotencyKey?: string;
237
+ /** Return a no-dispatch plan without provider calls or jobs. */
238
+ dryRun?: boolean;
239
+ }
240
+ interface SignalDiscoverySignal {
241
+ id?: string;
242
+ company: {
243
+ /** Every returned discovery signal is attributed to a distinct company. */
244
+ name: string;
245
+ domain: string;
246
+ linkedinUrl?: string | null;
247
+ };
248
+ title: string;
249
+ type: string;
250
+ summary: string;
251
+ eventDate?: string | null;
252
+ evidence: Array<{
253
+ url: string;
254
+ publishedAt: string;
255
+ source: string;
256
+ }>;
257
+ /** Compatibility alias for summary. */
258
+ content: string;
259
+ /** Compatibility alias for eventDate. */
260
+ date?: string | null;
261
+ detectedAt?: string | null;
262
+ sourceUrl?: string | null;
263
+ sourceType?: string | null;
264
+ confidence?: number | null;
265
+ classification?: Record<string, unknown> | string | null;
266
+ raw: Record<string, unknown>;
267
+ }
268
+ interface SignalDiscoveryCostGuardrail {
269
+ /** Strict ceiling: a qualified company signal must cost less than this amount to return. */
270
+ maxCostPerQualifiedSignalUsd: number;
271
+ projectedSourceCostUsd?: number | null;
272
+ maxSourceCostUsd?: number | null;
273
+ projectedCostPerRequestedCompanySignalUsd?: number | null;
274
+ sourceCostUsd?: number | null;
275
+ costSource?: 'observed' | 'catalog_bounded' | 'mixed' | 'unavailable';
276
+ qualifiedCompanySignalCount?: number;
277
+ returnedCompanySignalCount?: number;
278
+ /** Qualified signals retained on the same search run for later expansion. */
279
+ availableCompanySignalCount?: number;
280
+ /** Raw source candidate ceiling per selected source lane used to form the cohort. */
281
+ acquisitionCandidateLimit?: number;
282
+ /** Minimum qualified companies needed for the source receipt to stay below one cent each. */
283
+ minimumQualifiedCompanySignals?: number;
284
+ costPerQualifiedSignalUsd?: number | null;
285
+ withinLimit: boolean;
286
+ }
287
+ interface SignalDiscoveryResult {
288
+ success: boolean;
289
+ status: SignalDiscoveryStatus;
290
+ capability: 'signals_everything';
291
+ signalSearchRunId: string;
292
+ query: string;
293
+ requestedCount: number;
294
+ nextPollAfterSeconds?: number;
295
+ signals: SignalDiscoverySignal[];
296
+ signalCount: number;
297
+ /** Number of qualified company signals retained on signalSearchRunId. */
298
+ availableCompanySignalCount?: number;
299
+ sourceLanes?: string[];
300
+ evidenceValidation?: Record<string, unknown>;
301
+ costGuardrail?: SignalDiscoveryCostGuardrail;
302
+ warnings?: string[];
303
+ raw: Record<string, unknown>;
304
+ }
222
305
  interface SignalToCopyParams {
223
306
  companyDomain?: string;
224
307
  personName?: string;
@@ -310,6 +393,7 @@ declare class Signaliz {
310
393
  dryRun: true;
311
394
  }): Promise<CoreProductDryRunResult>;
312
395
  enrichCompanySignals(params: CompanySignalEnrichmentParams): Promise<CompanySignalEnrichmentResult>;
396
+ discoverSignals(params: SignalDiscoveryParams): Promise<SignalDiscoveryResult>;
313
397
  enrichCompanies(companies: CompanySignalEnrichmentParams[], options: BatchOptions & {
314
398
  dryRun: true;
315
399
  }): Promise<CoreProductDryRunResult>;
@@ -331,4 +415,4 @@ declare class Signaliz {
331
415
  health(): Promise<PlatformHealth>;
332
416
  }
333
417
 
334
- export { type BatchItemResult, type BatchOptions, type BatchResult, type CompanySignal, type CompanySignalEnrichmentParams, type CompanySignalEnrichmentResult, type ErrorType, type FindEmailParams, type FindEmailResult, type MCPToolInfo, type PlatformHealth, type SignalToCopyParams, type SignalToCopyResult, type SignalToCopyVariation, Signaliz, type SignalizConfig, SignalizError, type SignalizErrorData, type VerifyEmailBatchOptions, type VerifyEmailOptions, type VerifyEmailResult };
418
+ export { type BatchItemResult, type BatchOptions, type BatchResult, type CompanySignal, type CompanySignalEnrichmentParams, type CompanySignalEnrichmentResult, type ErrorType, type FindEmailParams, type FindEmailResult, type MCPToolInfo, type PlatformHealth, type SignalDiscoveryParams, type SignalDiscoveryResult, type SignalDiscoverySignal, type SignalDiscoverySource, type SignalDiscoveryStatus, type SignalToCopyParams, type SignalToCopyResult, type SignalToCopyVariation, Signaliz, type SignalizConfig, SignalizError, type SignalizErrorData, type VerifyEmailBatchOptions, type VerifyEmailOptions, type VerifyEmailResult };
package/dist/index.js CHANGED
@@ -495,6 +495,14 @@ var Signaliz = class {
495
495
  assertTerminalSignalResponse(data, "Company Signals");
496
496
  return normalizeCompanySignalResult(params, data);
497
497
  }
498
+ async discoverSignals(params) {
499
+ validateSignalDiscoveryParams(params);
500
+ const data = await this.client.post(
501
+ "api/v1/signals",
502
+ signalDiscoveryRequestBody(params)
503
+ );
504
+ return normalizeSignalDiscoveryResult(params, data);
505
+ }
498
506
  async enrichCompanies(companies, options) {
499
507
  validateBatchSize(companies);
500
508
  companies.forEach((params) => validateCoreProductMaxWaitMs(params.maxWaitMs));
@@ -1047,6 +1055,145 @@ function normalizeCompanySignalResult(params, data) {
1047
1055
  raw: data
1048
1056
  };
1049
1057
  }
1058
+ var SIGNAL_DISCOVERY_SOURCES = /* @__PURE__ */ new Set(["web", "news"]);
1059
+ var SIGNAL_DISCOVERY_STATUSES = /* @__PURE__ */ new Set([
1060
+ "planned",
1061
+ "queued",
1062
+ "processing",
1063
+ "completed",
1064
+ "completed_with_warnings",
1065
+ "failed"
1066
+ ]);
1067
+ function validateSignalDiscoveryParams(params) {
1068
+ const runId = typeof params.signalSearchRunId === "string" ? params.signalSearchRunId.trim() : "";
1069
+ const query = typeof params.query === "string" ? params.query.trim() : "";
1070
+ if (!runId && !query) {
1071
+ throw new TypeError("Signals Everything requires query or signalSearchRunId");
1072
+ }
1073
+ if (query && (query.length < 2 || query.length > 2e3)) {
1074
+ throw new RangeError("query must contain between 2 and 2000 characters");
1075
+ }
1076
+ if (params.limit !== void 0 && (!Number.isInteger(params.limit) || params.limit < 1 || params.limit > 1e3)) {
1077
+ throw new RangeError("limit must be an integer between 1 and 1000");
1078
+ }
1079
+ if (params.lookbackDays !== void 0 && (!Number.isInteger(params.lookbackDays) || params.lookbackDays < 1 || params.lookbackDays > 365)) {
1080
+ throw new RangeError("lookbackDays must be an integer between 1 and 365");
1081
+ }
1082
+ if (params.sources !== void 0 && (!Array.isArray(params.sources) || params.sources.length < 1 || params.sources.length > 2 || params.sources.some((source) => !SIGNAL_DISCOVERY_SOURCES.has(source)))) {
1083
+ throw new TypeError("sources must contain only web or news");
1084
+ }
1085
+ }
1086
+ function signalDiscoveryRequestBody(params) {
1087
+ const runId = typeof params.signalSearchRunId === "string" ? params.signalSearchRunId.trim() : "";
1088
+ if (runId) {
1089
+ return compact({
1090
+ signal_search_run_id: runId,
1091
+ // An explicit limit expands or narrows the retained qualified cohort;
1092
+ // omitting it preserves the original preview size.
1093
+ limit: params.limit,
1094
+ dry_run: params.dryRun,
1095
+ idempotency_key: params.idempotencyKey
1096
+ });
1097
+ }
1098
+ return compact({
1099
+ query: params.query?.trim(),
1100
+ limit: params.limit ?? 100,
1101
+ sources: params.sources,
1102
+ lookback_days: params.lookbackDays,
1103
+ dry_run: params.dryRun,
1104
+ idempotency_key: params.idempotencyKey
1105
+ });
1106
+ }
1107
+ function normalizeSignalDiscoveryResult(params, data) {
1108
+ const rawSignals = Array.isArray(data.signals) ? data.signals : [];
1109
+ const rawStatus = String(data.status || "").toLowerCase();
1110
+ const status = SIGNAL_DISCOVERY_STATUSES.has(rawStatus) ? rawStatus : rawSignals.length > 0 ? "completed" : "failed";
1111
+ const signals = rawSignals.map(normalizeSignalDiscoverySignal);
1112
+ return {
1113
+ success: data.success !== false,
1114
+ status,
1115
+ capability: "signals_everything",
1116
+ signalSearchRunId: String(data.signal_search_run_id ?? params.signalSearchRunId ?? ""),
1117
+ query: String(data.query ?? params.query ?? ""),
1118
+ requestedCount: Number(data.requested_count ?? params.limit ?? 100),
1119
+ nextPollAfterSeconds: typeof data.next_poll_after_seconds === "number" ? data.next_poll_after_seconds : void 0,
1120
+ signals,
1121
+ signalCount: signals.length,
1122
+ availableCompanySignalCount: Number.isFinite(Number(data.available_company_signal_count)) ? Number(data.available_company_signal_count) : void 0,
1123
+ sourceLanes: Array.isArray(data.source_lanes) ? data.source_lanes.filter((lane) => typeof lane === "string") : void 0,
1124
+ evidenceValidation: data.evidence_validation && typeof data.evidence_validation === "object" ? data.evidence_validation : void 0,
1125
+ costGuardrail: normalizeSignalDiscoveryCostGuardrail(data.cost_guardrail),
1126
+ warnings: Array.isArray(data.warnings) ? data.warnings.filter((warning) => typeof warning === "string") : void 0,
1127
+ raw: data
1128
+ };
1129
+ }
1130
+ function normalizeSignalDiscoveryCostGuardrail(value) {
1131
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1132
+ const guardrail = value;
1133
+ const maxCost = Number(guardrail.max_cost_per_qualified_signal_usd);
1134
+ const withinLimit = guardrail.within_limit === true;
1135
+ if (!Number.isFinite(maxCost)) return void 0;
1136
+ const numberOrNullable = (candidate) => {
1137
+ if (candidate === null) return null;
1138
+ const numeric = Number(candidate);
1139
+ return Number.isFinite(numeric) ? numeric : void 0;
1140
+ };
1141
+ const numberOrUndefined = (candidate) => {
1142
+ const numeric = Number(candidate);
1143
+ return Number.isFinite(numeric) ? numeric : void 0;
1144
+ };
1145
+ return {
1146
+ maxCostPerQualifiedSignalUsd: maxCost,
1147
+ projectedSourceCostUsd: numberOrNullable(guardrail.projected_source_cost_usd),
1148
+ maxSourceCostUsd: numberOrNullable(guardrail.max_source_cost_usd),
1149
+ projectedCostPerRequestedCompanySignalUsd: numberOrNullable(
1150
+ guardrail.projected_cost_per_requested_company_signal_usd
1151
+ ),
1152
+ sourceCostUsd: numberOrNullable(guardrail.source_cost_usd),
1153
+ costSource: ["observed", "catalog_bounded", "mixed", "unavailable"].includes(String(guardrail.cost_source)) ? String(guardrail.cost_source) : void 0,
1154
+ qualifiedCompanySignalCount: numberOrUndefined(guardrail.qualified_company_signal_count),
1155
+ returnedCompanySignalCount: numberOrUndefined(guardrail.returned_company_signal_count),
1156
+ availableCompanySignalCount: numberOrUndefined(guardrail.available_company_signal_count),
1157
+ acquisitionCandidateLimit: numberOrUndefined(guardrail.acquisition_candidate_limit),
1158
+ minimumQualifiedCompanySignals: numberOrUndefined(guardrail.minimum_qualified_company_signals),
1159
+ costPerQualifiedSignalUsd: numberOrNullable(guardrail.cost_per_qualified_signal_usd),
1160
+ withinLimit
1161
+ };
1162
+ }
1163
+ function normalizeSignalDiscoverySignal(value) {
1164
+ const signal = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1165
+ const company = signal.company && typeof signal.company === "object" && !Array.isArray(signal.company) ? signal.company : {};
1166
+ const companyName = String(company.name ?? signal.company_name ?? "").trim();
1167
+ const companyDomain = String(company.domain ?? signal.company_domain ?? "").trim();
1168
+ if (!companyName || !companyDomain) {
1169
+ throw new Error("Signals Everything response violated the company attribution contract.");
1170
+ }
1171
+ return {
1172
+ id: signal.id,
1173
+ company: {
1174
+ name: companyName,
1175
+ domain: companyDomain,
1176
+ linkedinUrl: company.linkedin_url ?? signal.company_linkedin_url ?? void 0
1177
+ },
1178
+ title: signal.title ?? "",
1179
+ type: signal.type ?? signal.signal_type ?? "unknown",
1180
+ summary: signal.summary ?? signal.content ?? signal.description ?? "",
1181
+ eventDate: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1182
+ evidence: Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
1183
+ url: String(item?.url ?? ""),
1184
+ publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
1185
+ source: String(item?.source ?? "")
1186
+ })).filter((item) => Boolean(item.url)) : [],
1187
+ content: signal.summary ?? signal.content ?? signal.description ?? "",
1188
+ date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1189
+ detectedAt: signal.event_date ?? signal.detected_at ?? null,
1190
+ sourceUrl: signal.source_url ?? signal.url ?? null,
1191
+ sourceType: signal.source_type ?? null,
1192
+ confidence: signal.confidence ?? signal.confidence_score ?? null,
1193
+ classification: signal.signal_classification ?? signal.classification ?? null,
1194
+ raw: signal
1195
+ };
1196
+ }
1050
1197
  function validateBatchSize(items) {
1051
1198
  if (!Array.isArray(items) || items.length === 0) {
1052
1199
  throw new Error("Signaliz batch requests require at least one item");
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Signaliz,
3
3
  SignalizError
4
- } from "./chunk-MC7EZ3BP.mjs";
4
+ } from "./chunk-QXMVHZIQ.mjs";
5
5
  export {
6
6
  Signaliz,
7
7
  SignalizError
@@ -499,6 +499,14 @@ var Signaliz = class {
499
499
  assertTerminalSignalResponse(data, "Company Signals");
500
500
  return normalizeCompanySignalResult(params, data);
501
501
  }
502
+ async discoverSignals(params) {
503
+ validateSignalDiscoveryParams(params);
504
+ const data = await this.client.post(
505
+ "api/v1/signals",
506
+ signalDiscoveryRequestBody(params)
507
+ );
508
+ return normalizeSignalDiscoveryResult(params, data);
509
+ }
502
510
  async enrichCompanies(companies, options) {
503
511
  validateBatchSize(companies);
504
512
  companies.forEach((params) => validateCoreProductMaxWaitMs(params.maxWaitMs));
@@ -1051,6 +1059,145 @@ function normalizeCompanySignalResult(params, data) {
1051
1059
  raw: data
1052
1060
  };
1053
1061
  }
1062
+ var SIGNAL_DISCOVERY_SOURCES = /* @__PURE__ */ new Set(["web", "news"]);
1063
+ var SIGNAL_DISCOVERY_STATUSES = /* @__PURE__ */ new Set([
1064
+ "planned",
1065
+ "queued",
1066
+ "processing",
1067
+ "completed",
1068
+ "completed_with_warnings",
1069
+ "failed"
1070
+ ]);
1071
+ function validateSignalDiscoveryParams(params) {
1072
+ const runId = typeof params.signalSearchRunId === "string" ? params.signalSearchRunId.trim() : "";
1073
+ const query = typeof params.query === "string" ? params.query.trim() : "";
1074
+ if (!runId && !query) {
1075
+ throw new TypeError("Signals Everything requires query or signalSearchRunId");
1076
+ }
1077
+ if (query && (query.length < 2 || query.length > 2e3)) {
1078
+ throw new RangeError("query must contain between 2 and 2000 characters");
1079
+ }
1080
+ if (params.limit !== void 0 && (!Number.isInteger(params.limit) || params.limit < 1 || params.limit > 1e3)) {
1081
+ throw new RangeError("limit must be an integer between 1 and 1000");
1082
+ }
1083
+ if (params.lookbackDays !== void 0 && (!Number.isInteger(params.lookbackDays) || params.lookbackDays < 1 || params.lookbackDays > 365)) {
1084
+ throw new RangeError("lookbackDays must be an integer between 1 and 365");
1085
+ }
1086
+ if (params.sources !== void 0 && (!Array.isArray(params.sources) || params.sources.length < 1 || params.sources.length > 2 || params.sources.some((source) => !SIGNAL_DISCOVERY_SOURCES.has(source)))) {
1087
+ throw new TypeError("sources must contain only web or news");
1088
+ }
1089
+ }
1090
+ function signalDiscoveryRequestBody(params) {
1091
+ const runId = typeof params.signalSearchRunId === "string" ? params.signalSearchRunId.trim() : "";
1092
+ if (runId) {
1093
+ return compact({
1094
+ signal_search_run_id: runId,
1095
+ // An explicit limit expands or narrows the retained qualified cohort;
1096
+ // omitting it preserves the original preview size.
1097
+ limit: params.limit,
1098
+ dry_run: params.dryRun,
1099
+ idempotency_key: params.idempotencyKey
1100
+ });
1101
+ }
1102
+ return compact({
1103
+ query: params.query?.trim(),
1104
+ limit: params.limit ?? 100,
1105
+ sources: params.sources,
1106
+ lookback_days: params.lookbackDays,
1107
+ dry_run: params.dryRun,
1108
+ idempotency_key: params.idempotencyKey
1109
+ });
1110
+ }
1111
+ function normalizeSignalDiscoveryResult(params, data) {
1112
+ const rawSignals = Array.isArray(data.signals) ? data.signals : [];
1113
+ const rawStatus = String(data.status || "").toLowerCase();
1114
+ const status = SIGNAL_DISCOVERY_STATUSES.has(rawStatus) ? rawStatus : rawSignals.length > 0 ? "completed" : "failed";
1115
+ const signals = rawSignals.map(normalizeSignalDiscoverySignal);
1116
+ return {
1117
+ success: data.success !== false,
1118
+ status,
1119
+ capability: "signals_everything",
1120
+ signalSearchRunId: String(data.signal_search_run_id ?? params.signalSearchRunId ?? ""),
1121
+ query: String(data.query ?? params.query ?? ""),
1122
+ requestedCount: Number(data.requested_count ?? params.limit ?? 100),
1123
+ nextPollAfterSeconds: typeof data.next_poll_after_seconds === "number" ? data.next_poll_after_seconds : void 0,
1124
+ signals,
1125
+ signalCount: signals.length,
1126
+ availableCompanySignalCount: Number.isFinite(Number(data.available_company_signal_count)) ? Number(data.available_company_signal_count) : void 0,
1127
+ sourceLanes: Array.isArray(data.source_lanes) ? data.source_lanes.filter((lane) => typeof lane === "string") : void 0,
1128
+ evidenceValidation: data.evidence_validation && typeof data.evidence_validation === "object" ? data.evidence_validation : void 0,
1129
+ costGuardrail: normalizeSignalDiscoveryCostGuardrail(data.cost_guardrail),
1130
+ warnings: Array.isArray(data.warnings) ? data.warnings.filter((warning) => typeof warning === "string") : void 0,
1131
+ raw: data
1132
+ };
1133
+ }
1134
+ function normalizeSignalDiscoveryCostGuardrail(value) {
1135
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1136
+ const guardrail = value;
1137
+ const maxCost = Number(guardrail.max_cost_per_qualified_signal_usd);
1138
+ const withinLimit = guardrail.within_limit === true;
1139
+ if (!Number.isFinite(maxCost)) return void 0;
1140
+ const numberOrNullable = (candidate) => {
1141
+ if (candidate === null) return null;
1142
+ const numeric = Number(candidate);
1143
+ return Number.isFinite(numeric) ? numeric : void 0;
1144
+ };
1145
+ const numberOrUndefined = (candidate) => {
1146
+ const numeric = Number(candidate);
1147
+ return Number.isFinite(numeric) ? numeric : void 0;
1148
+ };
1149
+ return {
1150
+ maxCostPerQualifiedSignalUsd: maxCost,
1151
+ projectedSourceCostUsd: numberOrNullable(guardrail.projected_source_cost_usd),
1152
+ maxSourceCostUsd: numberOrNullable(guardrail.max_source_cost_usd),
1153
+ projectedCostPerRequestedCompanySignalUsd: numberOrNullable(
1154
+ guardrail.projected_cost_per_requested_company_signal_usd
1155
+ ),
1156
+ sourceCostUsd: numberOrNullable(guardrail.source_cost_usd),
1157
+ costSource: ["observed", "catalog_bounded", "mixed", "unavailable"].includes(String(guardrail.cost_source)) ? String(guardrail.cost_source) : void 0,
1158
+ qualifiedCompanySignalCount: numberOrUndefined(guardrail.qualified_company_signal_count),
1159
+ returnedCompanySignalCount: numberOrUndefined(guardrail.returned_company_signal_count),
1160
+ availableCompanySignalCount: numberOrUndefined(guardrail.available_company_signal_count),
1161
+ acquisitionCandidateLimit: numberOrUndefined(guardrail.acquisition_candidate_limit),
1162
+ minimumQualifiedCompanySignals: numberOrUndefined(guardrail.minimum_qualified_company_signals),
1163
+ costPerQualifiedSignalUsd: numberOrNullable(guardrail.cost_per_qualified_signal_usd),
1164
+ withinLimit
1165
+ };
1166
+ }
1167
+ function normalizeSignalDiscoverySignal(value) {
1168
+ const signal = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1169
+ const company = signal.company && typeof signal.company === "object" && !Array.isArray(signal.company) ? signal.company : {};
1170
+ const companyName = String(company.name ?? signal.company_name ?? "").trim();
1171
+ const companyDomain = String(company.domain ?? signal.company_domain ?? "").trim();
1172
+ if (!companyName || !companyDomain) {
1173
+ throw new Error("Signals Everything response violated the company attribution contract.");
1174
+ }
1175
+ return {
1176
+ id: signal.id,
1177
+ company: {
1178
+ name: companyName,
1179
+ domain: companyDomain,
1180
+ linkedinUrl: company.linkedin_url ?? signal.company_linkedin_url ?? void 0
1181
+ },
1182
+ title: signal.title ?? "",
1183
+ type: signal.type ?? signal.signal_type ?? "unknown",
1184
+ summary: signal.summary ?? signal.content ?? signal.description ?? "",
1185
+ eventDate: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1186
+ evidence: Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
1187
+ url: String(item?.url ?? ""),
1188
+ publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
1189
+ source: String(item?.source ?? "")
1190
+ })).filter((item) => Boolean(item.url)) : [],
1191
+ content: signal.summary ?? signal.content ?? signal.description ?? "",
1192
+ date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1193
+ detectedAt: signal.event_date ?? signal.detected_at ?? null,
1194
+ sourceUrl: signal.source_url ?? signal.url ?? null,
1195
+ sourceType: signal.source_type ?? null,
1196
+ confidence: signal.confidence ?? signal.confidence_score ?? null,
1197
+ classification: signal.signal_classification ?? signal.classification ?? null,
1198
+ raw: signal
1199
+ };
1200
+ }
1054
1201
  function validateBatchSize(items) {
1055
1202
  if (!Array.isArray(items) || items.length === 0) {
1056
1203
  throw new Error("Signaliz batch requests require at least one item");
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Signaliz
4
- } from "./chunk-MC7EZ3BP.mjs";
4
+ } from "./chunk-QXMVHZIQ.mjs";
5
5
 
6
6
  // src/mcp-config.ts
7
7
  import * as fs from "fs";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@signaliz/sdk",
3
- "version": "1.0.53",
4
- "description": "Signaliz SDK for Find Email, Verify Email, Company Signal Enrichment, and Signal to Copy AI.",
3
+ "version": "1.0.55",
4
+ "description": "Signaliz SDK for Signals Everything, Find Email, Verify Email, Company Signal Enrichment, and Signal to Copy AI.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
@@ -24,7 +24,8 @@
24
24
  "email-finder",
25
25
  "email-verification",
26
26
  "company-signals",
27
- "signal-to-copy"
27
+ "signal-to-copy",
28
+ "signals-everything"
28
29
  ],
29
30
  "license": "MIT",
30
31
  "repository": {