deepline 0.1.76 → 0.1.78

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.d.mts CHANGED
@@ -775,6 +775,9 @@ interface PlayListItem {
775
775
  isDraftDirty?: boolean;
776
776
  inputSchema?: Record<string, unknown> | null;
777
777
  outputSchema?: Record<string, unknown> | null;
778
+ staticPipeline?: unknown;
779
+ currentRevision?: PlayRevisionSummary | null;
780
+ liveRevision?: PlayRevisionSummary | null;
778
781
  aliases?: string[];
779
782
  }
780
783
  interface PlayDescription {
@@ -788,6 +791,7 @@ interface PlayDescription {
788
791
  aliases: string[];
789
792
  inputSchema?: Record<string, unknown> | null;
790
793
  outputSchema?: Record<string, unknown> | null;
794
+ staticPipeline?: Record<string, unknown> | null;
791
795
  csvInput?: Record<string, unknown> | null;
792
796
  rowOutputSchema?: Record<string, unknown> | null;
793
797
  runCommand: string;
@@ -1953,7 +1957,9 @@ type PlayDatasetTransformOptions = {
1953
1957
  * Deepline keeps row progress, retries, memory use, and table output under
1954
1958
  * runtime control. Use `count()` and `peek()` for bounded inspection. Use
1955
1959
  * `materialize(limit)` or async iteration only when the dataset is intentionally
1956
- * small and bounded.
1960
+ * small and bounded. `PlayDataset` intentionally does not expose `.rows`,
1961
+ * `.toArray()`, or other array aliases; those hide the runtime cost of loading
1962
+ * persisted rows into memory.
1957
1963
  */
1958
1964
  interface PlayDataset<T> extends AsyncIterable<T> {
1959
1965
  readonly [PLAY_DATASET_BRAND]: true;
@@ -1997,6 +2003,37 @@ interface PlayDataset<T> extends AsyncIterable<T> {
1997
2003
  };
1998
2004
  }
1999
2005
 
2006
+ type EmailStatusVerdict = 'send' | 'send_with_caution' | 'verify_next' | 'hold' | 'drop';
2007
+ type EmailStatusValue = 'valid' | 'invalid' | 'catch_all' | 'valid_catch_all' | 'unknown' | 'do_not_mail' | 'spamtrap' | 'abuse' | 'disposable';
2008
+ type EmailStatusMapEntry = {
2009
+ status: EmailStatusValue;
2010
+ verdict?: EmailStatusVerdict;
2011
+ verified?: boolean;
2012
+ reason?: string;
2013
+ };
2014
+ type EmailStatusRule = EmailStatusMapEntry & {
2015
+ when: Record<string, string | number | boolean | null>;
2016
+ };
2017
+ type EmailStatusExtractorConfig = {
2018
+ provider: string;
2019
+ rawStatus?: string[];
2020
+ rawScore?: string[];
2021
+ valid?: string[];
2022
+ deliverability?: string[];
2023
+ catchAll?: string[];
2024
+ mxProvider?: string[];
2025
+ mxRecord?: string[];
2026
+ fraudScore?: string[];
2027
+ disposable?: string[];
2028
+ roleBased?: string[];
2029
+ freeEmail?: string[];
2030
+ abuse?: string[];
2031
+ spamtrap?: string[];
2032
+ suspect?: string[];
2033
+ statusMap?: Record<string, EmailStatusMapEntry>;
2034
+ rules?: EmailStatusRule[];
2035
+ };
2036
+
2000
2037
  type ToolResultExecutionMetadata = {
2001
2038
  idempotent: true;
2002
2039
  cached: boolean;
@@ -2017,6 +2054,7 @@ type ToolResultExtractorDescriptor = {
2017
2054
  transforms?: readonly string[];
2018
2055
  enum?: readonly string[];
2019
2056
  overrides?: readonly ToolResultExtractorOverride[];
2057
+ emailStatus?: EmailStatusExtractorConfig;
2020
2058
  };
2021
2059
  type ToolResultExtractorOverride = {
2022
2060
  paths: readonly string[];
@@ -2435,7 +2473,7 @@ interface DeeplinePlayRuntimeContext {
2435
2473
  * @param options - Run options.
2436
2474
  * @returns Program output.
2437
2475
  */
2438
- runSteps<TInput extends Record<string, unknown>, TOutput>(program: StepProgram<TInput, unknown, TOutput>, input: TInput, options?: {
2476
+ runSteps<TInput extends Record<string, unknown>, TOutput>(program: StepProgram<TInput, any, TOutput>, input: TInput, options?: {
2439
2477
  description?: string;
2440
2478
  }): Promise<TOutput>;
2441
2479
  /**
package/dist/index.d.ts CHANGED
@@ -775,6 +775,9 @@ interface PlayListItem {
775
775
  isDraftDirty?: boolean;
776
776
  inputSchema?: Record<string, unknown> | null;
777
777
  outputSchema?: Record<string, unknown> | null;
778
+ staticPipeline?: unknown;
779
+ currentRevision?: PlayRevisionSummary | null;
780
+ liveRevision?: PlayRevisionSummary | null;
778
781
  aliases?: string[];
779
782
  }
780
783
  interface PlayDescription {
@@ -788,6 +791,7 @@ interface PlayDescription {
788
791
  aliases: string[];
789
792
  inputSchema?: Record<string, unknown> | null;
790
793
  outputSchema?: Record<string, unknown> | null;
794
+ staticPipeline?: Record<string, unknown> | null;
791
795
  csvInput?: Record<string, unknown> | null;
792
796
  rowOutputSchema?: Record<string, unknown> | null;
793
797
  runCommand: string;
@@ -1953,7 +1957,9 @@ type PlayDatasetTransformOptions = {
1953
1957
  * Deepline keeps row progress, retries, memory use, and table output under
1954
1958
  * runtime control. Use `count()` and `peek()` for bounded inspection. Use
1955
1959
  * `materialize(limit)` or async iteration only when the dataset is intentionally
1956
- * small and bounded.
1960
+ * small and bounded. `PlayDataset` intentionally does not expose `.rows`,
1961
+ * `.toArray()`, or other array aliases; those hide the runtime cost of loading
1962
+ * persisted rows into memory.
1957
1963
  */
1958
1964
  interface PlayDataset<T> extends AsyncIterable<T> {
1959
1965
  readonly [PLAY_DATASET_BRAND]: true;
@@ -1997,6 +2003,37 @@ interface PlayDataset<T> extends AsyncIterable<T> {
1997
2003
  };
1998
2004
  }
1999
2005
 
2006
+ type EmailStatusVerdict = 'send' | 'send_with_caution' | 'verify_next' | 'hold' | 'drop';
2007
+ type EmailStatusValue = 'valid' | 'invalid' | 'catch_all' | 'valid_catch_all' | 'unknown' | 'do_not_mail' | 'spamtrap' | 'abuse' | 'disposable';
2008
+ type EmailStatusMapEntry = {
2009
+ status: EmailStatusValue;
2010
+ verdict?: EmailStatusVerdict;
2011
+ verified?: boolean;
2012
+ reason?: string;
2013
+ };
2014
+ type EmailStatusRule = EmailStatusMapEntry & {
2015
+ when: Record<string, string | number | boolean | null>;
2016
+ };
2017
+ type EmailStatusExtractorConfig = {
2018
+ provider: string;
2019
+ rawStatus?: string[];
2020
+ rawScore?: string[];
2021
+ valid?: string[];
2022
+ deliverability?: string[];
2023
+ catchAll?: string[];
2024
+ mxProvider?: string[];
2025
+ mxRecord?: string[];
2026
+ fraudScore?: string[];
2027
+ disposable?: string[];
2028
+ roleBased?: string[];
2029
+ freeEmail?: string[];
2030
+ abuse?: string[];
2031
+ spamtrap?: string[];
2032
+ suspect?: string[];
2033
+ statusMap?: Record<string, EmailStatusMapEntry>;
2034
+ rules?: EmailStatusRule[];
2035
+ };
2036
+
2000
2037
  type ToolResultExecutionMetadata = {
2001
2038
  idempotent: true;
2002
2039
  cached: boolean;
@@ -2017,6 +2054,7 @@ type ToolResultExtractorDescriptor = {
2017
2054
  transforms?: readonly string[];
2018
2055
  enum?: readonly string[];
2019
2056
  overrides?: readonly ToolResultExtractorOverride[];
2057
+ emailStatus?: EmailStatusExtractorConfig;
2020
2058
  };
2021
2059
  type ToolResultExtractorOverride = {
2022
2060
  paths: readonly string[];
@@ -2435,7 +2473,7 @@ interface DeeplinePlayRuntimeContext {
2435
2473
  * @param options - Run options.
2436
2474
  * @returns Program output.
2437
2475
  */
2438
- runSteps<TInput extends Record<string, unknown>, TOutput>(program: StepProgram<TInput, unknown, TOutput>, input: TInput, options?: {
2476
+ runSteps<TInput extends Record<string, unknown>, TOutput>(program: StepProgram<TInput, any, TOutput>, input: TInput, options?: {
2439
2477
  description?: string;
2440
2478
  }): Promise<TOutput>;
2441
2479
  /**
package/dist/index.js CHANGED
@@ -241,10 +241,10 @@ var import_node_path2 = require("path");
241
241
 
242
242
  // src/release.ts
243
243
  var SDK_RELEASE = {
244
- version: "0.1.76",
244
+ version: "0.1.78",
245
245
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
246
246
  supportPolicy: {
247
- latest: "0.1.76",
247
+ latest: "0.1.78",
248
248
  minimumSupported: "0.1.53",
249
249
  deprecatedBelow: "0.1.53"
250
250
  }
@@ -820,6 +820,7 @@ var DeeplineClient = class {
820
820
  aliases,
821
821
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
822
822
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
823
+ staticPipeline: isRecord(play.staticPipeline) ? play.staticPipeline : isRecord(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
823
824
  ...csvInput ? { csvInput } : {},
824
825
  ...rowOutputSchema ? { rowOutputSchema } : {},
825
826
  runCommand,
@@ -1906,6 +1907,160 @@ function formatPlayBootstrapFinderKindsForSentence() {
1906
1907
  return `${allButLast.join(", ")} or ${last}`;
1907
1908
  }
1908
1909
 
1910
+ // ../shared_libs/play-runtime/email-status.ts
1911
+ var DEFAULT_STATUS_MAP = {
1912
+ verified: { status: "valid", verdict: "send", verified: true },
1913
+ valid: { status: "valid", verdict: "send", verified: true },
1914
+ deliverable: { status: "valid", verdict: "send", verified: true },
1915
+ true: { status: "valid", verdict: "send", verified: true },
1916
+ invalid: { status: "invalid", verdict: "drop", verified: false },
1917
+ undeliverable: { status: "invalid", verdict: "drop", verified: false },
1918
+ false: { status: "invalid", verdict: "drop", verified: false },
1919
+ "catch-all": {
1920
+ status: "catch_all",
1921
+ verdict: "verify_next",
1922
+ verified: false
1923
+ },
1924
+ catch_all: {
1925
+ status: "catch_all",
1926
+ verdict: "verify_next",
1927
+ verified: false
1928
+ },
1929
+ valid_catch_all: {
1930
+ status: "valid_catch_all",
1931
+ verdict: "send_with_caution",
1932
+ verified: true
1933
+ },
1934
+ accept_all: {
1935
+ status: "catch_all",
1936
+ verdict: "verify_next",
1937
+ verified: false
1938
+ },
1939
+ unknown: { status: "unknown", verdict: "hold", verified: false },
1940
+ unavailable: { status: "unknown", verdict: "hold", verified: false },
1941
+ do_not_mail: { status: "do_not_mail", verdict: "drop", verified: false },
1942
+ spamtrap: { status: "spamtrap", verdict: "drop", verified: false },
1943
+ abuse: { status: "abuse", verdict: "drop", verified: false },
1944
+ disposable: { status: "disposable", verdict: "drop", verified: false }
1945
+ };
1946
+ function normalizeKey(value) {
1947
+ if (value == null) return null;
1948
+ if (typeof value === "boolean") return String(value);
1949
+ const normalized = String(value).trim().toLowerCase().replace(/\s+/g, "_");
1950
+ return normalized || null;
1951
+ }
1952
+ function boolish(value) {
1953
+ if (typeof value === "boolean") return value;
1954
+ if (typeof value === "number") return value === 1 ? true : value === 0 ? false : null;
1955
+ if (typeof value !== "string") return null;
1956
+ const normalized = value.trim().toLowerCase();
1957
+ if (["true", "yes", "y", "1"].includes(normalized)) return true;
1958
+ if (["false", "no", "n", "0"].includes(normalized)) return false;
1959
+ return null;
1960
+ }
1961
+ function numberish(value) {
1962
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1963
+ if (typeof value !== "string" || value.trim() === "") return null;
1964
+ const parsed = Number(value);
1965
+ return Number.isFinite(parsed) ? parsed : null;
1966
+ }
1967
+ function stringish(value) {
1968
+ return typeof value === "string" && value.trim() ? value.trim() : null;
1969
+ }
1970
+ function deliverability(value) {
1971
+ const normalized = normalizeKey(value);
1972
+ return normalized === "high" || normalized === "medium" || normalized === "low" ? normalized : "unknown";
1973
+ }
1974
+ function mxClass(mxProvider, mxRecord) {
1975
+ const haystack = `${stringish(mxProvider) ?? ""} ${stringish(mxRecord) ?? ""}`.toLowerCase();
1976
+ if (!haystack.trim()) return "unknown";
1977
+ if (/proofpoint|pphosted|mimecast|barracuda|ess\.barracudanetworks|ironport|cisco|iphmx|messagelabs|symantec/.test(
1978
+ haystack
1979
+ )) {
1980
+ return "security_gateway";
1981
+ }
1982
+ if (/aspmx\.l\.google|google|g-suite|google workspace/.test(haystack)) {
1983
+ return "workspace_mailbox";
1984
+ }
1985
+ if (/protection\.outlook|office365|microsoft|outlook|exchange online/.test(haystack)) {
1986
+ return "workspace_mailbox";
1987
+ }
1988
+ if (/gmail|yahoo|icloud|aol|hotmail/.test(haystack)) return "consumer_mailbox";
1989
+ if (/postfix|exim|sendmail|zimbra|plesk|cpanel|mail\./.test(haystack)) return "on_prem";
1990
+ return "unknown";
1991
+ }
1992
+ function entryForStatus(key, map) {
1993
+ if (!key) return null;
1994
+ return map?.[key] ?? DEFAULT_STATUS_MAP[key] ?? null;
1995
+ }
1996
+ function read(values, name) {
1997
+ return values[name];
1998
+ }
1999
+ function matchesRule(rule, values) {
2000
+ return Object.entries(rule.when).every(([key, expected]) => {
2001
+ const actual = read(values, key);
2002
+ if (key.endsWith("Lt")) {
2003
+ const source = numberish(read(values, key.slice(0, -2)));
2004
+ return typeof expected === "number" && source != null && source < expected;
2005
+ }
2006
+ if (typeof expected === "boolean") return boolish(actual) === expected;
2007
+ if (typeof expected === "number") return numberish(actual) === expected;
2008
+ return normalizeKey(actual) === normalizeKey(expected);
2009
+ });
2010
+ }
2011
+ function buildEmailStatus({
2012
+ config,
2013
+ values
2014
+ }) {
2015
+ const rawStatus = read(values, "rawStatus");
2016
+ const rawScore = numberish(read(values, "rawScore"));
2017
+ const valid = boolish(read(values, "valid"));
2018
+ const catchAll = boolish(read(values, "catchAll"));
2019
+ const disposable = boolish(read(values, "disposable"));
2020
+ const abuse = boolish(read(values, "abuse"));
2021
+ const spamtrap = boolish(read(values, "spamtrap"));
2022
+ const suspect = boolish(read(values, "suspect"));
2023
+ const rawKey = normalizeKey(rawStatus);
2024
+ const mapped = config.rules?.find((rule) => matchesRule(rule, values)) ?? entryForStatus(rawKey, config.statusMap) ?? entryForStatus(valid == null ? null : String(valid), config.statusMap);
2025
+ const status = mapped?.status ?? (disposable ? "disposable" : abuse ? "abuse" : spamtrap ? "spamtrap" : catchAll ? "catch_all" : valid === true ? "valid" : valid === false ? "invalid" : "unknown");
2026
+ const defaultVerdict = status === "valid" ? "send" : status === "valid_catch_all" ? "send_with_caution" : status === "catch_all" ? "verify_next" : status === "unknown" ? "hold" : "drop";
2027
+ const verdict = mapped?.verdict ?? defaultVerdict;
2028
+ const verified = mapped?.verified ?? (status === "valid" || status === "valid_catch_all" || verdict === "send");
2029
+ const reasons = [
2030
+ mapped?.reason,
2031
+ catchAll ? "catch_all_domain" : null,
2032
+ mxClass(read(values, "mxProvider"), read(values, "mxRecord")) === "security_gateway" ? "security_gateway_mx" : null,
2033
+ suspect ? "provider_marked_suspect" : null
2034
+ ].filter((reason) => typeof reason === "string");
2035
+ return {
2036
+ verdict,
2037
+ status,
2038
+ verified,
2039
+ confidence: rawScore,
2040
+ reasons,
2041
+ signals: {
2042
+ catch_all: catchAll,
2043
+ deliverability: deliverability(read(values, "deliverability")),
2044
+ mx_class: mxClass(read(values, "mxProvider"), read(values, "mxRecord")),
2045
+ mx_provider: stringish(read(values, "mxProvider")),
2046
+ mx_record: stringish(read(values, "mxRecord")),
2047
+ fraud_score: numberish(read(values, "fraudScore")),
2048
+ disposable,
2049
+ role_based: boolish(read(values, "roleBased")),
2050
+ free_email: boolish(read(values, "freeEmail")),
2051
+ abuse,
2052
+ spamtrap,
2053
+ suspect,
2054
+ valid
2055
+ },
2056
+ provider: {
2057
+ name: config.provider,
2058
+ raw_status: typeof rawStatus === "string" || typeof rawStatus === "boolean" || typeof rawStatus === "number" ? rawStatus : null,
2059
+ raw_score: rawScore
2060
+ }
2061
+ };
2062
+ }
2063
+
1909
2064
  // ../shared_libs/play-runtime/tool-result.ts
1910
2065
  var TARGET_FALLBACK_KEYS = {
1911
2066
  email: [/^email$/i, /^address$/i, /email/i],
@@ -2089,6 +2244,42 @@ function findFirstTargetByPath(result, paths) {
2089
2244
  }
2090
2245
  return null;
2091
2246
  }
2247
+ function firstValueForPaths(result, paths) {
2248
+ return findFirstTargetByPath(result, paths);
2249
+ }
2250
+ function buildEmailStatusTarget(result, descriptor) {
2251
+ const config = descriptor.emailStatus;
2252
+ if (!config) return null;
2253
+ const values = {};
2254
+ const pathSets = {
2255
+ rawStatus: config.rawStatus,
2256
+ rawScore: config.rawScore,
2257
+ valid: config.valid,
2258
+ deliverability: config.deliverability,
2259
+ catchAll: config.catchAll,
2260
+ mxProvider: config.mxProvider,
2261
+ mxRecord: config.mxRecord,
2262
+ fraudScore: config.fraudScore,
2263
+ disposable: config.disposable,
2264
+ roleBased: config.roleBased,
2265
+ freeEmail: config.freeEmail,
2266
+ abuse: config.abuse,
2267
+ spamtrap: config.spamtrap,
2268
+ suspect: config.suspect
2269
+ };
2270
+ let firstPath = null;
2271
+ for (const [name, paths] of Object.entries(pathSets)) {
2272
+ const match = firstValueForPaths(result, paths);
2273
+ if (!match) continue;
2274
+ values[name] = match.value;
2275
+ firstPath ??= match.path;
2276
+ }
2277
+ if (!firstPath) return null;
2278
+ return {
2279
+ path: firstPath,
2280
+ value: buildEmailStatus({ config, values })
2281
+ };
2282
+ }
2092
2283
  function findFirstTargetByKey(result, target, depth = 0, path = []) {
2093
2284
  if (depth > 6) return null;
2094
2285
  if (Array.isArray(result)) {
@@ -2238,6 +2429,11 @@ function deriveListKeys(input) {
2238
2429
  function buildTargets(result, extractors, targetGetters) {
2239
2430
  const targets = {};
2240
2431
  for (const [target, descriptor] of Object.entries(extractors ?? {})) {
2432
+ const emailStatusTarget = buildEmailStatusTarget(result, descriptor);
2433
+ if (emailStatusTarget) {
2434
+ targets[target] = emailStatusTarget;
2435
+ continue;
2436
+ }
2241
2437
  const fromExtractor = findFirstTargetByPath(result, descriptor.paths);
2242
2438
  if (!fromExtractor) continue;
2243
2439
  const transformed = coerceToEnum(
package/dist/index.mjs CHANGED
@@ -179,10 +179,10 @@ import { join as join2 } from "path";
179
179
 
180
180
  // src/release.ts
181
181
  var SDK_RELEASE = {
182
- version: "0.1.76",
182
+ version: "0.1.78",
183
183
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
184
184
  supportPolicy: {
185
- latest: "0.1.76",
185
+ latest: "0.1.78",
186
186
  minimumSupported: "0.1.53",
187
187
  deprecatedBelow: "0.1.53"
188
188
  }
@@ -758,6 +758,7 @@ var DeeplineClient = class {
758
758
  aliases,
759
759
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
760
760
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
761
+ staticPipeline: isRecord(play.staticPipeline) ? play.staticPipeline : isRecord(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
761
762
  ...csvInput ? { csvInput } : {},
762
763
  ...rowOutputSchema ? { rowOutputSchema } : {},
763
764
  runCommand,
@@ -1844,6 +1845,160 @@ function formatPlayBootstrapFinderKindsForSentence() {
1844
1845
  return `${allButLast.join(", ")} or ${last}`;
1845
1846
  }
1846
1847
 
1848
+ // ../shared_libs/play-runtime/email-status.ts
1849
+ var DEFAULT_STATUS_MAP = {
1850
+ verified: { status: "valid", verdict: "send", verified: true },
1851
+ valid: { status: "valid", verdict: "send", verified: true },
1852
+ deliverable: { status: "valid", verdict: "send", verified: true },
1853
+ true: { status: "valid", verdict: "send", verified: true },
1854
+ invalid: { status: "invalid", verdict: "drop", verified: false },
1855
+ undeliverable: { status: "invalid", verdict: "drop", verified: false },
1856
+ false: { status: "invalid", verdict: "drop", verified: false },
1857
+ "catch-all": {
1858
+ status: "catch_all",
1859
+ verdict: "verify_next",
1860
+ verified: false
1861
+ },
1862
+ catch_all: {
1863
+ status: "catch_all",
1864
+ verdict: "verify_next",
1865
+ verified: false
1866
+ },
1867
+ valid_catch_all: {
1868
+ status: "valid_catch_all",
1869
+ verdict: "send_with_caution",
1870
+ verified: true
1871
+ },
1872
+ accept_all: {
1873
+ status: "catch_all",
1874
+ verdict: "verify_next",
1875
+ verified: false
1876
+ },
1877
+ unknown: { status: "unknown", verdict: "hold", verified: false },
1878
+ unavailable: { status: "unknown", verdict: "hold", verified: false },
1879
+ do_not_mail: { status: "do_not_mail", verdict: "drop", verified: false },
1880
+ spamtrap: { status: "spamtrap", verdict: "drop", verified: false },
1881
+ abuse: { status: "abuse", verdict: "drop", verified: false },
1882
+ disposable: { status: "disposable", verdict: "drop", verified: false }
1883
+ };
1884
+ function normalizeKey(value) {
1885
+ if (value == null) return null;
1886
+ if (typeof value === "boolean") return String(value);
1887
+ const normalized = String(value).trim().toLowerCase().replace(/\s+/g, "_");
1888
+ return normalized || null;
1889
+ }
1890
+ function boolish(value) {
1891
+ if (typeof value === "boolean") return value;
1892
+ if (typeof value === "number") return value === 1 ? true : value === 0 ? false : null;
1893
+ if (typeof value !== "string") return null;
1894
+ const normalized = value.trim().toLowerCase();
1895
+ if (["true", "yes", "y", "1"].includes(normalized)) return true;
1896
+ if (["false", "no", "n", "0"].includes(normalized)) return false;
1897
+ return null;
1898
+ }
1899
+ function numberish(value) {
1900
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1901
+ if (typeof value !== "string" || value.trim() === "") return null;
1902
+ const parsed = Number(value);
1903
+ return Number.isFinite(parsed) ? parsed : null;
1904
+ }
1905
+ function stringish(value) {
1906
+ return typeof value === "string" && value.trim() ? value.trim() : null;
1907
+ }
1908
+ function deliverability(value) {
1909
+ const normalized = normalizeKey(value);
1910
+ return normalized === "high" || normalized === "medium" || normalized === "low" ? normalized : "unknown";
1911
+ }
1912
+ function mxClass(mxProvider, mxRecord) {
1913
+ const haystack = `${stringish(mxProvider) ?? ""} ${stringish(mxRecord) ?? ""}`.toLowerCase();
1914
+ if (!haystack.trim()) return "unknown";
1915
+ if (/proofpoint|pphosted|mimecast|barracuda|ess\.barracudanetworks|ironport|cisco|iphmx|messagelabs|symantec/.test(
1916
+ haystack
1917
+ )) {
1918
+ return "security_gateway";
1919
+ }
1920
+ if (/aspmx\.l\.google|google|g-suite|google workspace/.test(haystack)) {
1921
+ return "workspace_mailbox";
1922
+ }
1923
+ if (/protection\.outlook|office365|microsoft|outlook|exchange online/.test(haystack)) {
1924
+ return "workspace_mailbox";
1925
+ }
1926
+ if (/gmail|yahoo|icloud|aol|hotmail/.test(haystack)) return "consumer_mailbox";
1927
+ if (/postfix|exim|sendmail|zimbra|plesk|cpanel|mail\./.test(haystack)) return "on_prem";
1928
+ return "unknown";
1929
+ }
1930
+ function entryForStatus(key, map) {
1931
+ if (!key) return null;
1932
+ return map?.[key] ?? DEFAULT_STATUS_MAP[key] ?? null;
1933
+ }
1934
+ function read(values, name) {
1935
+ return values[name];
1936
+ }
1937
+ function matchesRule(rule, values) {
1938
+ return Object.entries(rule.when).every(([key, expected]) => {
1939
+ const actual = read(values, key);
1940
+ if (key.endsWith("Lt")) {
1941
+ const source = numberish(read(values, key.slice(0, -2)));
1942
+ return typeof expected === "number" && source != null && source < expected;
1943
+ }
1944
+ if (typeof expected === "boolean") return boolish(actual) === expected;
1945
+ if (typeof expected === "number") return numberish(actual) === expected;
1946
+ return normalizeKey(actual) === normalizeKey(expected);
1947
+ });
1948
+ }
1949
+ function buildEmailStatus({
1950
+ config,
1951
+ values
1952
+ }) {
1953
+ const rawStatus = read(values, "rawStatus");
1954
+ const rawScore = numberish(read(values, "rawScore"));
1955
+ const valid = boolish(read(values, "valid"));
1956
+ const catchAll = boolish(read(values, "catchAll"));
1957
+ const disposable = boolish(read(values, "disposable"));
1958
+ const abuse = boolish(read(values, "abuse"));
1959
+ const spamtrap = boolish(read(values, "spamtrap"));
1960
+ const suspect = boolish(read(values, "suspect"));
1961
+ const rawKey = normalizeKey(rawStatus);
1962
+ const mapped = config.rules?.find((rule) => matchesRule(rule, values)) ?? entryForStatus(rawKey, config.statusMap) ?? entryForStatus(valid == null ? null : String(valid), config.statusMap);
1963
+ const status = mapped?.status ?? (disposable ? "disposable" : abuse ? "abuse" : spamtrap ? "spamtrap" : catchAll ? "catch_all" : valid === true ? "valid" : valid === false ? "invalid" : "unknown");
1964
+ const defaultVerdict = status === "valid" ? "send" : status === "valid_catch_all" ? "send_with_caution" : status === "catch_all" ? "verify_next" : status === "unknown" ? "hold" : "drop";
1965
+ const verdict = mapped?.verdict ?? defaultVerdict;
1966
+ const verified = mapped?.verified ?? (status === "valid" || status === "valid_catch_all" || verdict === "send");
1967
+ const reasons = [
1968
+ mapped?.reason,
1969
+ catchAll ? "catch_all_domain" : null,
1970
+ mxClass(read(values, "mxProvider"), read(values, "mxRecord")) === "security_gateway" ? "security_gateway_mx" : null,
1971
+ suspect ? "provider_marked_suspect" : null
1972
+ ].filter((reason) => typeof reason === "string");
1973
+ return {
1974
+ verdict,
1975
+ status,
1976
+ verified,
1977
+ confidence: rawScore,
1978
+ reasons,
1979
+ signals: {
1980
+ catch_all: catchAll,
1981
+ deliverability: deliverability(read(values, "deliverability")),
1982
+ mx_class: mxClass(read(values, "mxProvider"), read(values, "mxRecord")),
1983
+ mx_provider: stringish(read(values, "mxProvider")),
1984
+ mx_record: stringish(read(values, "mxRecord")),
1985
+ fraud_score: numberish(read(values, "fraudScore")),
1986
+ disposable,
1987
+ role_based: boolish(read(values, "roleBased")),
1988
+ free_email: boolish(read(values, "freeEmail")),
1989
+ abuse,
1990
+ spamtrap,
1991
+ suspect,
1992
+ valid
1993
+ },
1994
+ provider: {
1995
+ name: config.provider,
1996
+ raw_status: typeof rawStatus === "string" || typeof rawStatus === "boolean" || typeof rawStatus === "number" ? rawStatus : null,
1997
+ raw_score: rawScore
1998
+ }
1999
+ };
2000
+ }
2001
+
1847
2002
  // ../shared_libs/play-runtime/tool-result.ts
1848
2003
  var TARGET_FALLBACK_KEYS = {
1849
2004
  email: [/^email$/i, /^address$/i, /email/i],
@@ -2027,6 +2182,42 @@ function findFirstTargetByPath(result, paths) {
2027
2182
  }
2028
2183
  return null;
2029
2184
  }
2185
+ function firstValueForPaths(result, paths) {
2186
+ return findFirstTargetByPath(result, paths);
2187
+ }
2188
+ function buildEmailStatusTarget(result, descriptor) {
2189
+ const config = descriptor.emailStatus;
2190
+ if (!config) return null;
2191
+ const values = {};
2192
+ const pathSets = {
2193
+ rawStatus: config.rawStatus,
2194
+ rawScore: config.rawScore,
2195
+ valid: config.valid,
2196
+ deliverability: config.deliverability,
2197
+ catchAll: config.catchAll,
2198
+ mxProvider: config.mxProvider,
2199
+ mxRecord: config.mxRecord,
2200
+ fraudScore: config.fraudScore,
2201
+ disposable: config.disposable,
2202
+ roleBased: config.roleBased,
2203
+ freeEmail: config.freeEmail,
2204
+ abuse: config.abuse,
2205
+ spamtrap: config.spamtrap,
2206
+ suspect: config.suspect
2207
+ };
2208
+ let firstPath = null;
2209
+ for (const [name, paths] of Object.entries(pathSets)) {
2210
+ const match = firstValueForPaths(result, paths);
2211
+ if (!match) continue;
2212
+ values[name] = match.value;
2213
+ firstPath ??= match.path;
2214
+ }
2215
+ if (!firstPath) return null;
2216
+ return {
2217
+ path: firstPath,
2218
+ value: buildEmailStatus({ config, values })
2219
+ };
2220
+ }
2030
2221
  function findFirstTargetByKey(result, target, depth = 0, path = []) {
2031
2222
  if (depth > 6) return null;
2032
2223
  if (Array.isArray(result)) {
@@ -2176,6 +2367,11 @@ function deriveListKeys(input) {
2176
2367
  function buildTargets(result, extractors, targetGetters) {
2177
2368
  const targets = {};
2178
2369
  for (const [target, descriptor] of Object.entries(extractors ?? {})) {
2370
+ const emailStatusTarget = buildEmailStatusTarget(result, descriptor);
2371
+ if (emailStatusTarget) {
2372
+ targets[target] = emailStatusTarget;
2373
+ continue;
2374
+ }
2179
2375
  const fromExtractor = findFirstTargetByPath(result, descriptor.paths);
2180
2376
  if (!fromExtractor) continue;
2181
2377
  const transformed = coerceToEnum(
@@ -565,6 +565,13 @@ export class DeeplineClient {
565
565
  outputSchema: options?.compact
566
566
  ? this.compactSchema(play.outputSchema)
567
567
  : (play.outputSchema ?? null),
568
+ staticPipeline: isRecord(play.staticPipeline)
569
+ ? play.staticPipeline
570
+ : isRecord(play.currentRevision?.staticPipeline)
571
+ ? play.currentRevision.staticPipeline
572
+ : isRecord(play.liveRevision?.staticPipeline)
573
+ ? play.liveRevision.staticPipeline
574
+ : null,
568
575
  ...(csvInput ? { csvInput } : {}),
569
576
  ...(rowOutputSchema ? { rowOutputSchema } : {}),
570
577
  runCommand,
@@ -540,7 +540,7 @@ export interface DeeplinePlayRuntimeContext {
540
540
  * @returns Program output.
541
541
  */
542
542
  runSteps<TInput extends Record<string, unknown>, TOutput>(
543
- program: StepProgram<TInput, unknown, TOutput>,
543
+ program: StepProgram<TInput, any, TOutput>,
544
544
  input: TInput,
545
545
  options?: { description?: string },
546
546
  ): Promise<TOutput>;
@@ -50,10 +50,10 @@ export type SdkRelease = {
50
50
  };
51
51
 
52
52
  export const SDK_RELEASE = {
53
- version: '0.1.76',
53
+ version: '0.1.78',
54
54
  apiContract: '2026-06-dataset-column-cell-stale-hard-cutover',
55
55
  supportPolicy: {
56
- latest: '0.1.76',
56
+ latest: '0.1.78',
57
57
  minimumSupported: '0.1.53',
58
58
  deprecatedBelow: '0.1.53',
59
59
  },