@signaliz/sdk 1.0.53 → 1.0.54

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,138 @@ 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
+ dry_run: params.dryRun,
1065
+ idempotency_key: params.idempotencyKey
1066
+ });
1067
+ }
1068
+ return compact({
1069
+ query: params.query?.trim(),
1070
+ limit: params.limit ?? 100,
1071
+ sources: params.sources,
1072
+ lookback_days: params.lookbackDays,
1073
+ dry_run: params.dryRun,
1074
+ idempotency_key: params.idempotencyKey
1075
+ });
1076
+ }
1077
+ function normalizeSignalDiscoveryResult(params, data) {
1078
+ const rawSignals = Array.isArray(data.signals) ? data.signals : [];
1079
+ const rawStatus = String(data.status || "").toLowerCase();
1080
+ const status = SIGNAL_DISCOVERY_STATUSES.has(rawStatus) ? rawStatus : rawSignals.length > 0 ? "completed" : "failed";
1081
+ const signals = rawSignals.map(normalizeSignalDiscoverySignal);
1082
+ return {
1083
+ success: data.success !== false,
1084
+ status,
1085
+ capability: "signals_everything",
1086
+ signalSearchRunId: String(data.signal_search_run_id ?? params.signalSearchRunId ?? ""),
1087
+ query: String(data.query ?? params.query ?? ""),
1088
+ requestedCount: Number(data.requested_count ?? params.limit ?? 100),
1089
+ nextPollAfterSeconds: typeof data.next_poll_after_seconds === "number" ? data.next_poll_after_seconds : void 0,
1090
+ signals,
1091
+ signalCount: signals.length,
1092
+ sourceLanes: Array.isArray(data.source_lanes) ? data.source_lanes.filter((lane) => typeof lane === "string") : void 0,
1093
+ evidenceValidation: data.evidence_validation && typeof data.evidence_validation === "object" ? data.evidence_validation : void 0,
1094
+ costGuardrail: normalizeSignalDiscoveryCostGuardrail(data.cost_guardrail),
1095
+ warnings: Array.isArray(data.warnings) ? data.warnings.filter((warning) => typeof warning === "string") : void 0,
1096
+ raw: data
1097
+ };
1098
+ }
1099
+ function normalizeSignalDiscoveryCostGuardrail(value) {
1100
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1101
+ const guardrail = value;
1102
+ const maxCost = Number(guardrail.max_cost_per_qualified_signal_usd);
1103
+ const withinLimit = guardrail.within_limit === true;
1104
+ if (!Number.isFinite(maxCost)) return void 0;
1105
+ const numberOrNullable = (candidate) => {
1106
+ if (candidate === null) return null;
1107
+ const numeric = Number(candidate);
1108
+ return Number.isFinite(numeric) ? numeric : void 0;
1109
+ };
1110
+ const numberOrUndefined = (candidate) => {
1111
+ const numeric = Number(candidate);
1112
+ return Number.isFinite(numeric) ? numeric : void 0;
1113
+ };
1114
+ return {
1115
+ maxCostPerQualifiedSignalUsd: maxCost,
1116
+ projectedSourceCostUsd: numberOrNullable(guardrail.projected_source_cost_usd),
1117
+ maxSourceCostUsd: numberOrNullable(guardrail.max_source_cost_usd),
1118
+ projectedCostPerRequestedCompanySignalUsd: numberOrNullable(
1119
+ guardrail.projected_cost_per_requested_company_signal_usd
1120
+ ),
1121
+ sourceCostUsd: numberOrNullable(guardrail.source_cost_usd),
1122
+ costSource: ["observed", "catalog_bounded", "mixed", "unavailable"].includes(String(guardrail.cost_source)) ? String(guardrail.cost_source) : void 0,
1123
+ qualifiedCompanySignalCount: numberOrUndefined(guardrail.qualified_company_signal_count),
1124
+ returnedCompanySignalCount: numberOrUndefined(guardrail.returned_company_signal_count),
1125
+ costPerQualifiedSignalUsd: numberOrNullable(guardrail.cost_per_qualified_signal_usd),
1126
+ withinLimit
1127
+ };
1128
+ }
1129
+ function normalizeSignalDiscoverySignal(value) {
1130
+ const signal = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1131
+ const company = signal.company && typeof signal.company === "object" && !Array.isArray(signal.company) ? signal.company : {};
1132
+ const companyName = String(company.name ?? signal.company_name ?? "").trim();
1133
+ const companyDomain = String(company.domain ?? signal.company_domain ?? "").trim();
1134
+ if (!companyName || !companyDomain) {
1135
+ throw new Error("Signals Everything response violated the company attribution contract.");
1136
+ }
1137
+ return {
1138
+ id: signal.id,
1139
+ company: {
1140
+ name: companyName,
1141
+ domain: companyDomain,
1142
+ linkedinUrl: company.linkedin_url ?? signal.company_linkedin_url ?? void 0
1143
+ },
1144
+ title: signal.title ?? "",
1145
+ type: signal.type ?? signal.signal_type ?? "unknown",
1146
+ summary: signal.summary ?? signal.content ?? signal.description ?? "",
1147
+ eventDate: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1148
+ evidence: Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
1149
+ url: String(item?.url ?? ""),
1150
+ publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
1151
+ source: String(item?.source ?? "")
1152
+ })).filter((item) => Boolean(item.url)) : [],
1153
+ content: signal.summary ?? signal.content ?? signal.description ?? "",
1154
+ date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1155
+ detectedAt: signal.event_date ?? signal.detected_at ?? null,
1156
+ sourceUrl: signal.source_url ?? signal.url ?? null,
1157
+ sourceType: signal.source_type ?? null,
1158
+ confidence: signal.confidence ?? signal.confidence_score ?? null,
1159
+ classification: signal.signal_classification ?? signal.classification ?? null,
1160
+ raw: signal
1161
+ };
1162
+ }
1023
1163
  function validateBatchSize(items) {
1024
1164
  if (!Array.isArray(items) || items.length === 0) {
1025
1165
  throw new Error("Signaliz batch requests require at least one item");
package/dist/index.d.mts CHANGED
@@ -219,6 +219,81 @@ 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
+ costPerQualifiedSignalUsd?: number | null;
279
+ withinLimit: boolean;
280
+ }
281
+ interface SignalDiscoveryResult {
282
+ success: boolean;
283
+ status: SignalDiscoveryStatus;
284
+ capability: 'signals_everything';
285
+ signalSearchRunId: string;
286
+ query: string;
287
+ requestedCount: number;
288
+ nextPollAfterSeconds?: number;
289
+ signals: SignalDiscoverySignal[];
290
+ signalCount: number;
291
+ sourceLanes?: string[];
292
+ evidenceValidation?: Record<string, unknown>;
293
+ costGuardrail?: SignalDiscoveryCostGuardrail;
294
+ warnings?: string[];
295
+ raw: Record<string, unknown>;
296
+ }
222
297
  interface SignalToCopyParams {
223
298
  companyDomain?: string;
224
299
  personName?: string;
@@ -310,6 +385,7 @@ declare class Signaliz {
310
385
  dryRun: true;
311
386
  }): Promise<CoreProductDryRunResult>;
312
387
  enrichCompanySignals(params: CompanySignalEnrichmentParams): Promise<CompanySignalEnrichmentResult>;
388
+ discoverSignals(params: SignalDiscoveryParams): Promise<SignalDiscoveryResult>;
313
389
  enrichCompanies(companies: CompanySignalEnrichmentParams[], options: BatchOptions & {
314
390
  dryRun: true;
315
391
  }): Promise<CoreProductDryRunResult>;
@@ -331,4 +407,4 @@ declare class Signaliz {
331
407
  health(): Promise<PlatformHealth>;
332
408
  }
333
409
 
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 };
410
+ 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,81 @@ 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
+ costPerQualifiedSignalUsd?: number | null;
279
+ withinLimit: boolean;
280
+ }
281
+ interface SignalDiscoveryResult {
282
+ success: boolean;
283
+ status: SignalDiscoveryStatus;
284
+ capability: 'signals_everything';
285
+ signalSearchRunId: string;
286
+ query: string;
287
+ requestedCount: number;
288
+ nextPollAfterSeconds?: number;
289
+ signals: SignalDiscoverySignal[];
290
+ signalCount: number;
291
+ sourceLanes?: string[];
292
+ evidenceValidation?: Record<string, unknown>;
293
+ costGuardrail?: SignalDiscoveryCostGuardrail;
294
+ warnings?: string[];
295
+ raw: Record<string, unknown>;
296
+ }
222
297
  interface SignalToCopyParams {
223
298
  companyDomain?: string;
224
299
  personName?: string;
@@ -310,6 +385,7 @@ declare class Signaliz {
310
385
  dryRun: true;
311
386
  }): Promise<CoreProductDryRunResult>;
312
387
  enrichCompanySignals(params: CompanySignalEnrichmentParams): Promise<CompanySignalEnrichmentResult>;
388
+ discoverSignals(params: SignalDiscoveryParams): Promise<SignalDiscoveryResult>;
313
389
  enrichCompanies(companies: CompanySignalEnrichmentParams[], options: BatchOptions & {
314
390
  dryRun: true;
315
391
  }): Promise<CoreProductDryRunResult>;
@@ -331,4 +407,4 @@ declare class Signaliz {
331
407
  health(): Promise<PlatformHealth>;
332
408
  }
333
409
 
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 };
410
+ 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,138 @@ 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
+ dry_run: params.dryRun,
1092
+ idempotency_key: params.idempotencyKey
1093
+ });
1094
+ }
1095
+ return compact({
1096
+ query: params.query?.trim(),
1097
+ limit: params.limit ?? 100,
1098
+ sources: params.sources,
1099
+ lookback_days: params.lookbackDays,
1100
+ dry_run: params.dryRun,
1101
+ idempotency_key: params.idempotencyKey
1102
+ });
1103
+ }
1104
+ function normalizeSignalDiscoveryResult(params, data) {
1105
+ const rawSignals = Array.isArray(data.signals) ? data.signals : [];
1106
+ const rawStatus = String(data.status || "").toLowerCase();
1107
+ const status = SIGNAL_DISCOVERY_STATUSES.has(rawStatus) ? rawStatus : rawSignals.length > 0 ? "completed" : "failed";
1108
+ const signals = rawSignals.map(normalizeSignalDiscoverySignal);
1109
+ return {
1110
+ success: data.success !== false,
1111
+ status,
1112
+ capability: "signals_everything",
1113
+ signalSearchRunId: String(data.signal_search_run_id ?? params.signalSearchRunId ?? ""),
1114
+ query: String(data.query ?? params.query ?? ""),
1115
+ requestedCount: Number(data.requested_count ?? params.limit ?? 100),
1116
+ nextPollAfterSeconds: typeof data.next_poll_after_seconds === "number" ? data.next_poll_after_seconds : void 0,
1117
+ signals,
1118
+ signalCount: signals.length,
1119
+ sourceLanes: Array.isArray(data.source_lanes) ? data.source_lanes.filter((lane) => typeof lane === "string") : void 0,
1120
+ evidenceValidation: data.evidence_validation && typeof data.evidence_validation === "object" ? data.evidence_validation : void 0,
1121
+ costGuardrail: normalizeSignalDiscoveryCostGuardrail(data.cost_guardrail),
1122
+ warnings: Array.isArray(data.warnings) ? data.warnings.filter((warning) => typeof warning === "string") : void 0,
1123
+ raw: data
1124
+ };
1125
+ }
1126
+ function normalizeSignalDiscoveryCostGuardrail(value) {
1127
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1128
+ const guardrail = value;
1129
+ const maxCost = Number(guardrail.max_cost_per_qualified_signal_usd);
1130
+ const withinLimit = guardrail.within_limit === true;
1131
+ if (!Number.isFinite(maxCost)) return void 0;
1132
+ const numberOrNullable = (candidate) => {
1133
+ if (candidate === null) return null;
1134
+ const numeric = Number(candidate);
1135
+ return Number.isFinite(numeric) ? numeric : void 0;
1136
+ };
1137
+ const numberOrUndefined = (candidate) => {
1138
+ const numeric = Number(candidate);
1139
+ return Number.isFinite(numeric) ? numeric : void 0;
1140
+ };
1141
+ return {
1142
+ maxCostPerQualifiedSignalUsd: maxCost,
1143
+ projectedSourceCostUsd: numberOrNullable(guardrail.projected_source_cost_usd),
1144
+ maxSourceCostUsd: numberOrNullable(guardrail.max_source_cost_usd),
1145
+ projectedCostPerRequestedCompanySignalUsd: numberOrNullable(
1146
+ guardrail.projected_cost_per_requested_company_signal_usd
1147
+ ),
1148
+ sourceCostUsd: numberOrNullable(guardrail.source_cost_usd),
1149
+ costSource: ["observed", "catalog_bounded", "mixed", "unavailable"].includes(String(guardrail.cost_source)) ? String(guardrail.cost_source) : void 0,
1150
+ qualifiedCompanySignalCount: numberOrUndefined(guardrail.qualified_company_signal_count),
1151
+ returnedCompanySignalCount: numberOrUndefined(guardrail.returned_company_signal_count),
1152
+ costPerQualifiedSignalUsd: numberOrNullable(guardrail.cost_per_qualified_signal_usd),
1153
+ withinLimit
1154
+ };
1155
+ }
1156
+ function normalizeSignalDiscoverySignal(value) {
1157
+ const signal = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1158
+ const company = signal.company && typeof signal.company === "object" && !Array.isArray(signal.company) ? signal.company : {};
1159
+ const companyName = String(company.name ?? signal.company_name ?? "").trim();
1160
+ const companyDomain = String(company.domain ?? signal.company_domain ?? "").trim();
1161
+ if (!companyName || !companyDomain) {
1162
+ throw new Error("Signals Everything response violated the company attribution contract.");
1163
+ }
1164
+ return {
1165
+ id: signal.id,
1166
+ company: {
1167
+ name: companyName,
1168
+ domain: companyDomain,
1169
+ linkedinUrl: company.linkedin_url ?? signal.company_linkedin_url ?? void 0
1170
+ },
1171
+ title: signal.title ?? "",
1172
+ type: signal.type ?? signal.signal_type ?? "unknown",
1173
+ summary: signal.summary ?? signal.content ?? signal.description ?? "",
1174
+ eventDate: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1175
+ evidence: Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
1176
+ url: String(item?.url ?? ""),
1177
+ publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
1178
+ source: String(item?.source ?? "")
1179
+ })).filter((item) => Boolean(item.url)) : [],
1180
+ content: signal.summary ?? signal.content ?? signal.description ?? "",
1181
+ date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1182
+ detectedAt: signal.event_date ?? signal.detected_at ?? null,
1183
+ sourceUrl: signal.source_url ?? signal.url ?? null,
1184
+ sourceType: signal.source_type ?? null,
1185
+ confidence: signal.confidence ?? signal.confidence_score ?? null,
1186
+ classification: signal.signal_classification ?? signal.classification ?? null,
1187
+ raw: signal
1188
+ };
1189
+ }
1050
1190
  function validateBatchSize(items) {
1051
1191
  if (!Array.isArray(items) || items.length === 0) {
1052
1192
  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-W4JH6JJA.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,138 @@ 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
+ dry_run: params.dryRun,
1096
+ idempotency_key: params.idempotencyKey
1097
+ });
1098
+ }
1099
+ return compact({
1100
+ query: params.query?.trim(),
1101
+ limit: params.limit ?? 100,
1102
+ sources: params.sources,
1103
+ lookback_days: params.lookbackDays,
1104
+ dry_run: params.dryRun,
1105
+ idempotency_key: params.idempotencyKey
1106
+ });
1107
+ }
1108
+ function normalizeSignalDiscoveryResult(params, data) {
1109
+ const rawSignals = Array.isArray(data.signals) ? data.signals : [];
1110
+ const rawStatus = String(data.status || "").toLowerCase();
1111
+ const status = SIGNAL_DISCOVERY_STATUSES.has(rawStatus) ? rawStatus : rawSignals.length > 0 ? "completed" : "failed";
1112
+ const signals = rawSignals.map(normalizeSignalDiscoverySignal);
1113
+ return {
1114
+ success: data.success !== false,
1115
+ status,
1116
+ capability: "signals_everything",
1117
+ signalSearchRunId: String(data.signal_search_run_id ?? params.signalSearchRunId ?? ""),
1118
+ query: String(data.query ?? params.query ?? ""),
1119
+ requestedCount: Number(data.requested_count ?? params.limit ?? 100),
1120
+ nextPollAfterSeconds: typeof data.next_poll_after_seconds === "number" ? data.next_poll_after_seconds : void 0,
1121
+ signals,
1122
+ signalCount: signals.length,
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
+ costPerQualifiedSignalUsd: numberOrNullable(guardrail.cost_per_qualified_signal_usd),
1157
+ withinLimit
1158
+ };
1159
+ }
1160
+ function normalizeSignalDiscoverySignal(value) {
1161
+ const signal = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1162
+ const company = signal.company && typeof signal.company === "object" && !Array.isArray(signal.company) ? signal.company : {};
1163
+ const companyName = String(company.name ?? signal.company_name ?? "").trim();
1164
+ const companyDomain = String(company.domain ?? signal.company_domain ?? "").trim();
1165
+ if (!companyName || !companyDomain) {
1166
+ throw new Error("Signals Everything response violated the company attribution contract.");
1167
+ }
1168
+ return {
1169
+ id: signal.id,
1170
+ company: {
1171
+ name: companyName,
1172
+ domain: companyDomain,
1173
+ linkedinUrl: company.linkedin_url ?? signal.company_linkedin_url ?? void 0
1174
+ },
1175
+ title: signal.title ?? "",
1176
+ type: signal.type ?? signal.signal_type ?? "unknown",
1177
+ summary: signal.summary ?? signal.content ?? signal.description ?? "",
1178
+ eventDate: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1179
+ evidence: Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
1180
+ url: String(item?.url ?? ""),
1181
+ publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
1182
+ source: String(item?.source ?? "")
1183
+ })).filter((item) => Boolean(item.url)) : [],
1184
+ content: signal.summary ?? signal.content ?? signal.description ?? "",
1185
+ date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
1186
+ detectedAt: signal.event_date ?? signal.detected_at ?? null,
1187
+ sourceUrl: signal.source_url ?? signal.url ?? null,
1188
+ sourceType: signal.source_type ?? null,
1189
+ confidence: signal.confidence ?? signal.confidence_score ?? null,
1190
+ classification: signal.signal_classification ?? signal.classification ?? null,
1191
+ raw: signal
1192
+ };
1193
+ }
1054
1194
  function validateBatchSize(items) {
1055
1195
  if (!Array.isArray(items) || items.length === 0) {
1056
1196
  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-W4JH6JJA.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.54",
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": {