🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@usekaval/kaval

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@usekaval/kaval - npm Package Compare versions

Comparing version
0.3.1
to
0.4.0
+478
dist/offer-search.d.ts
/** Public REST request and response types for the current review-only Offer Search surface. */
export type ProductIdentifierScheme = "gtin" | "upc" | "ean" | "isbn" | "mpn" | "manufacturer_sku" | "model";
export interface ProductIdentifier {
scheme: ProductIdentifierScheme;
value: string;
issuer?: string;
}
export interface ProductAttribute {
key: string;
value: string | number | boolean;
unit?: string;
}
export interface PackSpec {
count: number;
units_per_item?: number;
unit?: string;
}
export interface ProductTarget {
schema_revision: number;
family?: {
brand?: string;
name?: string;
category?: string;
};
name?: string;
identifiers: ProductIdentifier[];
attributes: ProductAttribute[];
pack?: PackSpec;
}
export interface ProductFamily {
schema_revision: number;
family_id: string;
brand: string;
name: string;
category?: string;
identifiers: ProductIdentifier[];
}
export interface ProductVariant {
schema_revision: number;
variant_id: string;
family: ProductFamily;
name: string;
identifiers: ProductIdentifier[];
attributes: ProductAttribute[];
pack: PackSpec;
}
export type ProductCondition = "new" | "open_box" | "refurbished" | "used_like_new" | "used_good" | "used_acceptable" | "unknown";
export type SellerKind = "brand_direct" | "authorized_retailer" | "marketplace" | "independent_retailer" | "unknown";
interface SubstitutionBase {
rule_id: string;
rationale: string;
maximum_materiality: "low" | "medium" | "high" | "critical";
}
export type PermittedSubstitution = (SubstitutionBase & {
kind: "attribute";
key: string;
requested_value: string | number | boolean;
permitted_value: string | number | boolean;
requested_unit?: string;
permitted_unit?: string;
}) | (SubstitutionBase & {
kind: "pack";
requested: PackSpec;
permitted: PackSpec;
}) | (SubstitutionBase & {
kind: "condition";
requested: ProductCondition;
permitted: ProductCondition;
}) | (SubstitutionBase & {
kind: "variant";
requested_identifiers: ProductIdentifier[];
permitted_variant_id: string;
permitted_identifiers: ProductIdentifier[];
});
export interface OfferSearchInput {
schema_revision: number;
request_id: string;
raw_description: string;
target: ProductTarget;
requested_condition: ProductCondition;
destination: {
country_code: string;
region?: string;
postal_code?: string;
};
match_policy: {
identity_requirement: "shared_identifier" | "shared_identifier_or_complete_attributes";
required_identifier_schemes: ProductIdentifierScheme[];
required_attribute_keys: string[];
permitted_substitutions: PermittedSubstitution[];
};
seller_policy: {
allowed_seller_ids: string[];
blocked_seller_ids: string[];
allowed_kinds: SellerKind[];
require_authorized: boolean;
};
destination_policy: {
require_eligible: boolean;
require_exact_region: boolean;
require_exact_postal_code: boolean;
};
price_policy: {
currency: string;
maximum_landed_total_minor?: number;
require_complete_landed_total: boolean;
allow_estimated_components: boolean;
allow_member_price: boolean;
allow_subscription_price: boolean;
allow_coupon_price: boolean;
allow_installment_display: boolean;
allow_trade_in_price: boolean;
};
source_policy: {
allowed_source_ids: string[];
blocked_source_ids: string[];
require_origin_evidence: boolean;
};
intended_action: {
description: string;
materiality: "low" | "medium" | "high" | "critical";
reversibility: "reversible" | "partially_reversible" | "irreversible";
};
freshness_maximum_age_ms: number;
max_results: number;
minimum_unique_sellers: number;
deadline_ms: number;
maximum_cost_micro_usd: number;
maximum_search_calls: number;
maximum_fetches: number;
}
export interface Money {
amount_minor: number;
currency: string;
}
export interface ExtractedOriginOffer {
evidence_kind: "json_ld" | "embedded_product_json" | "product_meta";
source_block_index: number;
jsonld_product_index: number;
jsonld_offer_index: number | null;
variant: ProductVariant;
title: string;
purchase_url: string;
seller_name: string | null;
condition: ProductCondition;
availability: "in_stock" | "out_of_stock" | "preorder" | "unknown";
item_price: Money | null;
destination_eligibility: "unknown";
landed_price_complete: false;
extraction_gaps: string[];
}
export type OfferConflictCode = "FAMILY_BRAND_CONFLICT" | "FAMILY_NAME_CONFLICT" | "IDENTIFIER_CONFLICT" | "IDENTIFIER_AMBIGUOUS" | "IDENTIFIER_MISSING" | "ATTRIBUTE_CONFLICT" | "ATTRIBUTE_MISSING" | "PACK_CONFLICT" | "PACK_INCOMPLETE" | "CONDITION_CONFLICT" | "SELLER_BLOCKED" | "SELLER_NOT_ALLOWED" | "SELLER_KIND_NOT_ALLOWED" | "SELLER_AUTHORIZATION_REQUIRED" | "DESTINATION_CONFLICT" | "DESTINATION_INELIGIBLE" | "DESTINATION_UNKNOWN" | "CURRENCY_CONFLICT" | "PRICE_LIMIT_EXCEEDED" | "PRICE_INCOMPLETE" | "MATERIAL_EVIDENCE_MISSING" | "OBSERVATION_EXPIRED";
export interface OfferMatchAssessment {
state: "exact" | "permitted_substitute" | "ambiguous" | "conflict" | "insufficient_identity";
conflict_codes: OfferConflictCode[];
matched_identifier_schemes: ProductIdentifierScheme[];
matched_attribute_keys: string[];
applied_substitutions: PermittedSubstitution[];
explanation: string;
}
export interface LiveOfferSearchCandidate {
candidate_id: `sha256:${string}`;
origin_url: string;
source_id: string;
discovered_by: string[];
discovery_metadata: Array<{
provider: string;
title: string | null;
}>;
origin_evidence: {
kind: ExtractedOriginOffer["evidence_kind"];
content_digest: `sha256:${string}`;
source_block_index: number;
jsonld_product_index: number;
jsonld_offer_index: number | null;
};
origin_offer: ExtractedOriginOffer;
identity: OfferMatchAssessment;
/** Current shadow output can only be queued for review or rejected. */
disposition: "review" | "rejected";
gaps: string[];
reason_codes: string[];
/** Destination-aware checkout evidence. Its action remains REVIEW-only. */
checkout?: CommerceCheckoutVerification;
}
export type CommerceSourceFamily = "catalog" | "merchant_feed" | "retailer_origin" | "shopping_search" | "open_web";
export interface CommerceCheckoutResolverDescriptor {
schema_revision: 1;
source_id: string;
adapter_revision: string;
execution_mode: "recorded_fixture" | "live";
estimated_cost_micro_usd: number;
}
export interface CommerceCheckoutObservation {
destination_eligibility: "eligible" | "ineligible" | "unknown";
availability: "in_stock" | "out_of_stock" | "preorder" | "unknown";
seller_authorized: boolean | null;
item_price: Money | null;
shipping_price: Money | null;
tax_price: Money | null;
mandatory_fees: Money | null;
declared_landed_total: Money | null;
quote_id: string | null;
evidence_digest: `sha256:${string}`;
observed_at: string;
expires_at: string;
}
export type LandedPriceValidationReason = "EXPECTED_CURRENCY_INVALID" | "ITEM_PRICE_MISSING" | "SHIPPING_PRICE_MISSING" | "TAX_PRICE_MISSING" | "MANDATORY_FEES_MISSING" | "DECLARED_LANDED_TOTAL_MISSING" | "MONEY_VALUE_INVALID" | "PRICE_CURRENCY_CONFLICT" | "LANDED_TOTAL_OVERFLOW" | "LANDED_TOTAL_ARITHMETIC_MISMATCH";
export interface LandedPriceValidation {
state: "complete" | "incomplete" | "invalid" | "inconsistent";
expected_currency: string;
calculated_landed_total: Money | null;
reason_codes: LandedPriceValidationReason[];
}
export interface CommerceCheckoutVerification {
status: "verified" | "review_required" | "rejected" | "operational_failure";
resolver: CommerceCheckoutResolverDescriptor | null;
request_digest: `sha256:${string}`;
observation: CommerceCheckoutObservation | null;
landed_price_validation: LandedPriceValidation;
action: {
state: "REVIEW";
action_authorized: false;
reason_codes: string[];
};
actual_cost_micro_usd: number;
version_receipt: string | null;
operational_error_code: "UPSTREAM_UNAVAILABLE" | "DESTINATION_UNSUPPORTED" | "MALFORMED_RESPONSE" | "RIGHTS_REVOKED" | "CANCELLED" | null;
}
export interface CommercePlannedSource {
source_id: string;
family: CommerceSourceFamily;
call_kind: "search" | "fetch";
independence_group: string;
estimated_cost_micro_usd: number;
field_guarantees: string[];
health_state: "healthy" | "degraded";
concurrency_limit: number;
supports_cancellation: boolean;
role: "structured_acquisition" | "origin_verification" | "discovery_tail";
winner_must_be_origin_verified: boolean;
}
export interface CommerceSourcePlan {
schema_revision: number;
request_id: string;
request_digest: `sha256:${string}`;
supplier_registry_schema_revision: number;
supplier_registry_digest: `sha256:${string}`;
waves: Array<{
wave: number;
purpose: "structured_authoritative" | "retailer_origin" | "unresolved_identity_and_coverage";
sources: CommercePlannedSource[];
}>;
receipt: {
schema_revision: number;
request_id: string;
coverage_claim: "bounded_not_comprehensive";
name_only_target: boolean;
minimum_independent_families_required: number;
planned_independent_families: CommerceSourceFamily[];
planned_independence_groups: string[];
independence_requirement_met: boolean;
origin_verification_required: true;
origin_verification_planned: boolean;
origin_verification_source_ids: string[];
eligible_supplier_count_before_budget: number;
total_planned_cost_micro_usd: number;
total_planned_search_calls: number;
total_planned_fetches: number;
exclusions: Array<{
source_id: string;
family: CommerceSourceFamily;
call_kind: "search" | "fetch";
estimated_cost_micro_usd: number;
reason: string;
}>;
};
}
export interface CommerceAcquisitionSourceLedgerEntry {
source_id: string;
family: CommerceSourceFamily;
disposition: "succeeded" | "failed" | "cancelled" | "prohibited" | "deferred" | "unsearched";
reason_code: string;
}
export interface CommerceAcquisitionRunReport {
schema_revision: 1;
request_digest: `sha256:${string}`;
plan: CommerceSourcePlan;
/** Full planner state is retained for audit/replay and may add fields within schema revision 1. */
state: Readonly<Record<string, unknown>>;
stop: {
reason: Exclude<OfferSearchStopReason, "sufficient_offers">;
explanation: string;
};
calls: Array<Readonly<Record<string, unknown>>>;
records: Array<Readonly<Record<string, unknown>>>;
source_ledger: CommerceAcquisitionSourceLedgerEntry[];
coverage: {
claim: "bounded_not_comprehensive";
attempted_source_families: CommerceSourceFamily[];
unique_candidate_keys: number;
unique_sellers: number;
unsearched_source_count: number;
prohibited_source_count: number;
failed_source_count: number;
};
deduplication: {
source_records: number;
unique_urls: number;
unique_variants: number;
unique_sellers: number;
unique_listings: number;
unique_offers: number;
independent_information_origins: number;
};
replay_digest: `sha256:${string}`;
}
export interface LiveOfferSearchAcquisitionTrace {
coverage_claim: "bounded_not_comprehensive";
plan: CommerceSourcePlan;
plan_digest: `sha256:${string}`;
source_ledger: CommerceAcquisitionSourceLedgerEntry[];
adapter_run?: CommerceAcquisitionRunReport;
}
/** Digests that bind one persisted evidence generation to one exact downstream action slot. */
export interface CommerceActionBinding {
action_slot_key: string;
action_input_digest: `sha256:${string}`;
action_consequence_digest: `sha256:${string}`;
}
export type CommerceActionTimeGateState = "current_review_only" | "not_found" | "stale_generation" | "binding_mismatch" | "expired" | "invalidated" | "refresh_required" | "source_revoked" | "retention_unavailable" | "integrity_failed" | "operational_failure";
/** Exact body accepted by POST /v1/search-offers/gate. Tenant identity is server-derived. */
export interface CommerceActionTimeGateInput {
dependency_id: string;
generation_id: string;
generation_number: number;
generation_digest: `sha256:${string}`;
action_binding: CommerceActionBinding;
}
/**
* A final-fence read of one persisted offer generation. Commerce remains review-only: even a
* current generation returns REVIEW with permission withheld.
*/
export interface CommerceActionTimeGateResult {
state: CommerceActionTimeGateState;
disposition: "REVIEW";
permission: "withheld";
reason_codes: string[];
checked_at: string;
final_fence_checked: boolean;
generation_id?: string;
generation_number?: number;
generation_digest?: `sha256:${string}`;
expires_at?: string;
}
export type CommerceOfferSearchLifecycle = {
persistence: "persisted";
dependency_id: string;
generation_id: string;
generation_number: number;
generation_digest: `sha256:${string}`;
selected_candidate_id: `sha256:${string}`;
expires_at: string;
action_binding: CommerceActionBinding;
action_time_gate: CommerceActionTimeGateResult;
} | {
persistence: "not_created";
reason_codes: string[];
action_time_gate: Pick<CommerceActionTimeGateResult, "disposition" | "permission" | "reason_codes" | "checked_at" | "final_fence_checked"> & {
state: "not_found";
};
};
export type CommerceSourceAttemptErrorCode = "INVALID_DISCOVERY_URL" | "DISCOVERY_IDENTIFIER_MISMATCH" | "ORIGIN_BLOCKED" | "ORIGIN_HTTP_ERROR" | "ORIGIN_JSONLD_INVALID" | "ORIGIN_TIMEOUT" | "ORIGIN_UNAVAILABLE" | "SEARCH_UNAVAILABLE" | "BUDGET_EXHAUSTED" | "DEADLINE_REACHED" | "CANCELLED" | "COVERAGE_SATISFIED";
export interface CommerceLiveSourceAttempt {
sequence: number;
kind: "search" | "origin_fetch";
call_attempted: boolean;
source_id: string;
provider: string | null;
query: string | null;
url: string | null;
outcome: "succeeded" | "empty" | "failed" | "blocked" | "skipped" | "cancelled";
error_code: CommerceSourceAttemptErrorCode | null;
latency_ms: number;
cost_micro_usd: number;
reuse: "executed" | "tenant_private_cache";
avoided_cost_micro_usd: number;
result_count: number | null;
http_status: number | null;
bytes_received: number | null;
}
export type OfferSearchStopReason = "coverage_satisfied" | "sufficient_offers" | "source_exhausted" | "budget_exhausted" | "deadline_reached" | "cancelled" | "upstream_unavailable" | "policy_blocked";
export interface LiveOfferSearchResult {
schema_revision: 2;
request_id: string;
request_digest: `sha256:${string}`;
status: "complete" | "partial" | "failed";
/** Offer Search is shadow-only and cannot authorize a quote or purchase. */
action: {
state: "NEEDS_REVIEW" | "NO_RELIABLE_OFFER";
reason_codes: string[];
};
stop_reason: OfferSearchStopReason;
query: string | null;
candidates: LiveOfferSearchCandidate[];
source_attempts: CommerceLiveSourceAttempt[];
receipt: {
search_calls: number;
fetch_calls: number;
providers_configured: number;
providers_succeeded: number;
cost_micro_usd: number;
cost_basis: "reserved_ceiling";
provider_estimated_cost_micro_usd: number | null;
provider_estimated_cost_reported_search_calls: number;
discovery_cache_hits: number;
cost_avoided_micro_usd: number;
elapsed_ms: number;
};
started_at: string;
completed_at: string;
/** Auditable rights, coverage, and attempted-source trace. */
acquisition?: LiveOfferSearchAcquisitionTrace;
/** Present only when the hosted server has a configured durable commerce lifecycle. */
lifecycle?: CommerceOfferSearchLifecycle;
}
export type OfferSearchProgressStage = "accepted" | "acquisition" | "verification" | "coverage" | "candidate_provisional" | "candidate" | "warning";
interface OfferSearchProgressEventBase {
sequence: number;
at: string;
request_id: string;
message: string;
authority: "research_only";
action_state: "REVIEW";
details: Readonly<Record<string, unknown>>;
}
export interface OfferSearchStageEvent extends OfferSearchProgressEventBase {
type: Exclude<OfferSearchProgressStage, "candidate_provisional">;
}
/** Origin-verified research observed before final selection and lifecycle persistence. */
export interface OfferSearchProvisionalCandidateEvent extends OfferSearchProgressEventBase {
type: "candidate_provisional";
details: Readonly<{
request_digest: `sha256:${string}`;
origin_sequence: number;
publication_state: "provisional";
durable: false;
actionable: false;
permission: "withheld";
final_inclusion: "not_yet_determined";
candidate: LiveOfferSearchCandidate;
}>;
}
export type OfferSearchProgressEvent = OfferSearchStageEvent | OfferSearchProvisionalCandidateEvent;
/** A same-key completed-operation replay performs no new provider work. */
export interface OfferSearchReplayEvent {
type: "replay";
sequence: number;
replayed_at: string;
request_id: string;
request_digest: `sha256:${string}`;
authority: "research_only";
action_state: "REVIEW";
}
export type OfferSearchStreamEvent = OfferSearchProgressEvent | OfferSearchReplayEvent | {
type: "final";
sequence: number;
result: LiveOfferSearchResult;
};
/** Validate a public progressive event before exposing it to an agent. */
export declare function reviewOnlyOfferSearchProgressEvent(value: unknown): OfferSearchProgressEvent;
/** Validate the content-free event emitted for a durable same-key replay. */
export declare function reviewOnlyOfferSearchReplayEvent(value: unknown, expectedRequestId?: string): OfferSearchReplayEvent;
/** Reject authority drift and validate the exact public action-time commerce gate response. */
export declare function reviewOnlyCommerceActionTimeGateResult(value: unknown, expectedGeneration?: Pick<CommerceActionTimeGateInput, "generation_id" | "generation_number" | "generation_digest">): CommerceActionTimeGateResult;
/** Reject a drifted commerce response before a caller can mistake shadow research for permission. */
export declare function reviewOnlyOfferSearchResult(value: unknown, expectedRequestId?: string): LiveOfferSearchResult;
export {};
/** Public REST request and response types for the current review-only Offer Search surface. */
function record(value) {
return typeof value === "object" && value !== null && !Array.isArray(value)
? value
: null;
}
const COMMERCE_DIGEST = /^sha256:[0-9a-f]{64}$/u;
const ACTION_TIME_GATE_STATES = new Set([
"current_review_only",
"not_found",
"stale_generation",
"binding_mismatch",
"expired",
"invalidated",
"refresh_required",
"source_revoked",
"retention_unavailable",
"integrity_failed",
"operational_failure",
]);
function stringArray(value) {
return (Array.isArray(value) && value.every((item) => typeof item === "string"));
}
function digest(value) {
return typeof value === "string" && COMMERCE_DIGEST.test(value);
}
function actionBinding(value) {
const binding = record(value);
return (typeof binding?.["action_slot_key"] === "string" &&
binding["action_slot_key"].length > 0 &&
digest(binding["action_input_digest"]) &&
digest(binding["action_consequence_digest"]) &&
binding["action_input_digest"] !== binding["action_consequence_digest"]);
}
/** Detect permission-shaped fields anywhere in a commerce response, including future extensions. */
function containsCommerceAuthority(value) {
if (Array.isArray(value))
return value.some(containsCommerceAuthority);
const current = record(value);
if (!current)
return false;
for (const [key, nested] of Object.entries(current)) {
const authorityToken = typeof nested === "string" ? nested.toUpperCase() : undefined;
if (((key === "safe_to_quote" ||
key === "action_authorized" ||
key === "execution_allowed" ||
key === "executionAllowed" ||
key === "act") &&
nested === true) ||
(key === "permission" && nested !== "withheld") ||
((key === "decision" || key === "disposition" || key === "state") &&
(authorityToken === "ALLOW" ||
authorityToken === "BLOCK" ||
authorityToken === "SAFE_TO_QUOTE")) ||
containsCommerceAuthority(nested)) {
return true;
}
}
return false;
}
const OFFER_SEARCH_PROGRESS_STAGES = new Set([
"accepted",
"acquisition",
"verification",
"coverage",
"candidate_provisional",
"candidate",
"warning",
]);
/** Validate a public progressive event before exposing it to an agent. */
export function reviewOnlyOfferSearchProgressEvent(value) {
const event = record(value);
if (!event ||
!OFFER_SEARCH_PROGRESS_STAGES.has(event["type"]) ||
!Number.isInteger(event["sequence"]) ||
event["sequence"] < 0 ||
typeof event["at"] !== "string" ||
typeof event["request_id"] !== "string" ||
typeof event["message"] !== "string" ||
event["authority"] !== "research_only" ||
event["action_state"] !== "REVIEW" ||
record(event["details"]) === null ||
containsCommerceAuthority(event)) {
throw new TypeError("Offer Search stream returned an invalid or authority-bearing progress event");
}
if (event["type"] === "candidate_provisional") {
const details = record(event["details"]);
const candidate = record(details?.["candidate"]);
if (!details ||
!digest(details["request_digest"]) ||
!Number.isInteger(details["origin_sequence"]) ||
details["origin_sequence"] < 0 ||
details["publication_state"] !== "provisional" ||
details["durable"] !== false ||
details["actionable"] !== false ||
details["permission"] !== "withheld" ||
details["final_inclusion"] !== "not_yet_determined" ||
!candidate ||
!digest(candidate["candidate_id"]) ||
typeof candidate["origin_url"] !== "string" ||
typeof candidate["source_id"] !== "string" ||
(candidate["disposition"] !== "review" &&
candidate["disposition"] !== "rejected")) {
throw new TypeError("Offer Search stream returned an invalid provisional candidate event");
}
}
return value;
}
/** Validate the content-free event emitted for a durable same-key replay. */
export function reviewOnlyOfferSearchReplayEvent(value, expectedRequestId) {
const event = record(value);
if (!event ||
event["type"] !== "replay" ||
!Number.isInteger(event["sequence"]) ||
event["sequence"] < 0 ||
typeof event["replayed_at"] !== "string" ||
typeof event["request_id"] !== "string" ||
event["request_id"].length === 0 ||
!digest(event["request_digest"]) ||
(expectedRequestId !== undefined &&
event["request_id"] !== expectedRequestId) ||
event["authority"] !== "research_only" ||
event["action_state"] !== "REVIEW" ||
containsCommerceAuthority(event)) {
throw new TypeError("Offer Search stream returned an invalid or authority-bearing replay event");
}
return value;
}
/** Reject authority drift and validate the exact public action-time commerce gate response. */
export function reviewOnlyCommerceActionTimeGateResult(value, expectedGeneration) {
const gate = record(value);
if (!gate ||
!ACTION_TIME_GATE_STATES.has(gate["state"]) ||
gate["disposition"] !== "REVIEW" ||
gate["permission"] !== "withheld" ||
!stringArray(gate["reason_codes"]) ||
typeof gate["checked_at"] !== "string" ||
typeof gate["final_fence_checked"] !== "boolean" ||
(gate["generation_id"] !== undefined &&
typeof gate["generation_id"] !== "string") ||
(gate["generation_number"] !== undefined &&
(!Number.isInteger(gate["generation_number"]) ||
gate["generation_number"] <= 0)) ||
(gate["generation_digest"] !== undefined &&
!digest(gate["generation_digest"])) ||
(gate["expires_at"] !== undefined &&
typeof gate["expires_at"] !== "string") ||
containsCommerceAuthority(gate)) {
throw new TypeError("Offer Search action-time gate returned an invalid or authority-bearing response; commerce permission must remain withheld");
}
if (gate["state"] === "current_review_only" &&
(gate["final_fence_checked"] !== true ||
typeof gate["generation_id"] !== "string" ||
gate["generation_id"].length === 0 ||
!Number.isInteger(gate["generation_number"]) ||
gate["generation_number"] <= 0 ||
!digest(gate["generation_digest"]) ||
(expectedGeneration !== undefined &&
(gate["generation_id"] !== expectedGeneration.generation_id ||
gate["generation_number"] !== expectedGeneration.generation_number ||
gate["generation_digest"] !== expectedGeneration.generation_digest)))) {
throw new TypeError("Offer Search action-time gate returned an invalid or authority-bearing response; commerce permission must remain withheld");
}
return value;
}
function commerceLifecycle(value, candidates) {
const lifecycle = record(value);
if (lifecycle?.["persistence"] === "persisted") {
if (typeof lifecycle["dependency_id"] !== "string" ||
typeof lifecycle["generation_id"] !== "string" ||
!Number.isInteger(lifecycle["generation_number"]) ||
lifecycle["generation_number"] <= 0 ||
!digest(lifecycle["generation_digest"]) ||
!digest(lifecycle["selected_candidate_id"]) ||
typeof lifecycle["expires_at"] !== "string" ||
!actionBinding(lifecycle["action_binding"])) {
throw new TypeError("Offer Search returned invalid lifecycle metadata");
}
const selectedCandidateMatches = candidates.filter((candidate) => record(candidate)?.["candidate_id"] ===
lifecycle["selected_candidate_id"]).length;
if (selectedCandidateMatches !== 1) {
throw new TypeError("Offer Search returned invalid lifecycle metadata");
}
const expectedGeneration = {
generation_id: lifecycle["generation_id"],
generation_number: lifecycle["generation_number"],
generation_digest: lifecycle["generation_digest"],
};
const gate = reviewOnlyCommerceActionTimeGateResult(lifecycle["action_time_gate"], expectedGeneration);
if ((gate.generation_id !== undefined &&
gate.generation_id !== expectedGeneration.generation_id) ||
(gate.generation_number !== undefined &&
gate.generation_number !== expectedGeneration.generation_number) ||
(gate.generation_digest !== undefined &&
gate.generation_digest !== expectedGeneration.generation_digest)) {
throw new TypeError("Offer Search returned invalid lifecycle metadata");
}
return value;
}
if (lifecycle?.["persistence"] === "not_created" &&
stringArray(lifecycle["reason_codes"])) {
const gate = reviewOnlyCommerceActionTimeGateResult(lifecycle["action_time_gate"]);
if (gate.state === "not_found") {
return value;
}
}
throw new TypeError("Offer Search returned invalid lifecycle metadata");
}
/** Reject a drifted commerce response before a caller can mistake shadow research for permission. */
export function reviewOnlyOfferSearchResult(value, expectedRequestId) {
const result = record(value);
if (typeof result?.["request_id"] !== "string" ||
result["request_id"].length === 0 ||
!digest(result["request_digest"])) {
throw new TypeError("Offer Search returned an invalid request ID or digest binding");
}
if (expectedRequestId !== undefined &&
result["request_id"] !== expectedRequestId) {
throw new TypeError("Offer Search result is bound to another request");
}
const action = record(result?.["action"]);
const candidates = result?.["candidates"];
if (result?.["schema_revision"] !== 2 ||
result?.["decision"] === "ALLOW" ||
result?.["safe_to_quote"] === true ||
(action?.["state"] !== "NEEDS_REVIEW" &&
action?.["state"] !== "NO_RELIABLE_OFFER") ||
action?.["decision"] === "ALLOW" ||
action?.["safe_to_quote"] === true ||
containsCommerceAuthority(result) ||
!Array.isArray(candidates) ||
candidates.some((candidate) => {
const candidateRecord = record(candidate);
const disposition = candidateRecord?.["disposition"];
return ((disposition !== "review" && disposition !== "rejected") ||
candidateRecord?.["safe_to_quote"] === true);
})) {
throw new TypeError("Offer Search returned a non-review-only response; shadow results cannot authorize an action");
}
if (result["lifecycle"] !== undefined) {
commerceLifecycle(result["lifecycle"], candidates);
}
return value;
}
+13
-2
/**
* @usekaval/kaval — the freshness gate for AI. A typed, dependency-light HTTP client for the kaval API.
* @usekaval/kaval — the evidence gate for AI agents. A typed, dependency-light HTTP client for the Kaval API.
* Mirrors the Python SDK (`pip install kaval`). Uses the global `fetch` (Node 18+, browsers, edge).
*/
import type { AuditInput, ProofGateInput, ProofGateResult, ProofPacket } from "./proof.js";
import { type CommerceActionTimeGateInput, type CommerceActionTimeGateResult, type LiveOfferSearchResult, type OfferSearchInput, type OfferSearchStreamEvent } from "./offer-search.js";
export type * from "./proof.js";
export type * from "./offer-search.js";
export type VerdictStatus = "current" | "stale" | "contradicted" | "unsupported" | "conflicting" | "insufficient";

@@ -159,3 +161,3 @@ /** Speed/depth tier for a verify() call. */

}
/** The kaval client: a belief your system holds in, a typed freshness verdict out. */
/** The Kaval client: evidence in, an action-bound decision or review-only research result out. */
export declare class Kaval {

@@ -185,2 +187,11 @@ private readonly base;

monitor(input: MonitorInput, options?: RequestOptions): Promise<MonitorResult>;
/** Search the accessible configured web for exact or possible offers. Current results are
* research-only: action.state is NEEDS_REVIEW or NO_RELIABLE_OFFER, never permission to quote. */
searchOffers(input: OfferSearchInput, options?: RequestOptions): Promise<LiveOfferSearchResult>;
/** Stream bounded, review-only acquisition progress followed by one canonical final result.
* Cancellation closes the response body and propagates to the hosted acquisition operation. */
streamOfferSearch(input: OfferSearchInput, options?: RequestOptions): AsyncGenerator<OfferSearchStreamEvent, LiveOfferSearchResult, void>;
/** Re-read one persisted offer generation at the exact action boundary. This final fence always
* returns REVIEW with commerce permission withheld; it never authorizes quoting or purchasing. */
gateOfferSearch(input: CommerceActionTimeGateInput, options?: Pick<RequestOptions, "signal" | "timeoutMs">): Promise<CommerceActionTimeGateResult>;
/** Build, sign, and persist a complete action-bound proof packet. */

@@ -187,0 +198,0 @@ audit(input: AuditInput, options?: RequestOptions): Promise<ProofPacket>;

/**
* @usekaval/kaval — the freshness gate for AI. A typed, dependency-light HTTP client for the kaval API.
* @usekaval/kaval — the evidence gate for AI agents. A typed, dependency-light HTTP client for the Kaval API.
* Mirrors the Python SDK (`pip install kaval`). Uses the global `fetch` (Node 18+, browsers, edge).
*/
import { reviewOnlyCommerceActionTimeGateResult, reviewOnlyOfferSearchProgressEvent, reviewOnlyOfferSearchReplayEvent, reviewOnlyOfferSearchResult, } from "./offer-search.js";
/** Thrown on any non-2xx response. */

@@ -104,3 +105,3 @@ export class KavalError extends Error {

}
/** The kaval client: a belief your system holds in, a typed freshness verdict out. */
/** The Kaval client: evidence in, an action-bound decision or review-only research result out. */
export class Kaval {

@@ -176,13 +177,20 @@ base;

}
async post(path, body) {
const res = await this.f(`${this.base}${path}`, {
method: "POST",
headers: this.headers,
// JSON.stringify omits `undefined` keys, so optional params drop out automatically.
body: JSON.stringify(body),
});
const payload = await res.json().catch(() => null);
if (!res.ok)
throw new KavalError(res.status, payload);
return payload;
async post(path, body, options = {}) {
const request = requestSignal(options.signal, options.timeoutMs === undefined ? this.timeoutMs : options.timeoutMs);
try {
const res = await this.f(`${this.base}${path}`, {
method: "POST",
headers: this.headers,
signal: request.signal,
// JSON.stringify omits `undefined` keys, so optional params drop out automatically.
body: JSON.stringify(body),
});
const payload = await res.json().catch(() => null);
if (!res.ok)
throw new KavalError(res.status, payload);
return payload;
}
finally {
request.cleanup();
}
}

@@ -209,2 +217,183 @@ /** Pre-action gate: the verdict plus `act`. Treat `act === false` as "re-fetch before relying on it". */

}
/** Search the accessible configured web for exact or possible offers. Current results are
* research-only: action.state is NEEDS_REVIEW or NO_RELIABLE_OFFER, never permission to quote. */
async searchOffers(input, options) {
const result = await this.billablePost("/v1/search-offers", input, options);
return reviewOnlyOfferSearchResult(result, input.request_id);
}
/** Stream bounded, review-only acquisition progress followed by one canonical final result.
* Cancellation closes the response body and propagates to the hosted acquisition operation. */
async *streamOfferSearch(input, options = {}) {
const idempotencyKey = options.idempotencyKey ?? generatedIdempotencyKey();
const headers = {
...this.headers,
accept: "text/event-stream",
"idempotency-key": idempotencyKey,
};
const request = requestSignal(options.signal, options.timeoutMs === undefined ? this.timeoutMs : options.timeoutMs);
let response;
let reader;
try {
for (let attempt = 0; attempt < MAX_BILLABLE_ATTEMPTS; attempt += 1) {
try {
response = await this.f(`${this.base}/v1/search-offers`, {
method: "POST",
headers,
signal: request.signal,
body: JSON.stringify(input),
});
}
catch (error) {
if (request.signal?.aborted || attempt + 1 >= MAX_BILLABLE_ATTEMPTS) {
throw attachIdempotencyKey(error, idempotencyKey);
}
continue;
}
if (response.ok)
break;
const responseText = await response.text();
let payload = responseText;
try {
payload = JSON.parse(responseText);
}
catch {
// A non-Kaval intermediary may return a plain-text error.
}
const code = apiErrorCode(payload);
if (attempt + 1 < MAX_BILLABLE_ATTEMPTS &&
code !== undefined &&
AMBIGUOUS_IDEMPOTENCY_CODES.has(code)) {
response = undefined;
continue;
}
throw new KavalError(response.status, payload, idempotencyKey);
}
if (!response?.ok)
throw new Error("unreachable Offer Search stream request state");
if (!response.headers.get("content-type")?.includes("text/event-stream")) {
throw attachIdempotencyKey(new TypeError("Offer Search stream returned a non-SSE response"), idempotencyKey);
}
if (!response.body) {
throw attachIdempotencyKey(new TypeError("Offer Search stream response has no body"), idempotencyKey);
}
reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let lastSequence = -1;
let finalResult;
let streamRequestDigest;
const consumeFrame = (frame) => {
const lines = frame.split("\n");
const eventName = lines
.find((line) => line.startsWith("event:"))
?.slice("event:".length)
.trim();
const idText = lines
.find((line) => line.startsWith("id:"))
?.slice("id:".length)
.trim();
const dataText = lines
.filter((line) => line.startsWith("data:"))
.map((line) => line.slice("data:".length).trimStart())
.join("\n");
if (!eventName || !dataText)
return null;
let payload;
try {
payload = JSON.parse(dataText);
}
catch (error) {
throw attachIdempotencyKey(error, idempotencyKey);
}
const id = idText === undefined ? undefined : Number(idText);
if (idText !== undefined && (!Number.isInteger(id) || id < 0)) {
throw new TypeError("Offer Search stream event ID is invalid");
}
if (eventName === "error") {
const error = payload;
throw new KavalError(typeof error?.status === "number" ? error.status : 500, payload, idempotencyKey);
}
if (eventName === "final") {
const result = reviewOnlyOfferSearchResult(payload, input.request_id);
if (streamRequestDigest !== undefined &&
result.request_digest !== streamRequestDigest) {
throw new TypeError("Offer Search stream events are bound to another final result");
}
const sequence = Number.isInteger(id) ? id : lastSequence + 1;
if (sequence <= lastSequence) {
throw new TypeError("Offer Search stream sequence is not monotonic");
}
lastSequence = sequence;
finalResult = result;
return { type: "final", sequence, result };
}
if (eventName === "replay") {
const event = reviewOnlyOfferSearchReplayEvent(payload, input.request_id);
if ((id !== undefined && id !== event.sequence) ||
event.sequence <= lastSequence) {
throw new TypeError("Offer Search stream replay sequence is invalid");
}
if (streamRequestDigest !== undefined &&
event.request_digest !== streamRequestDigest) {
throw new TypeError("Offer Search replay request binding changed");
}
streamRequestDigest = event.request_digest;
lastSequence = event.sequence;
return event;
}
const event = reviewOnlyOfferSearchProgressEvent(payload);
if (event.type !== eventName ||
event.request_id !== input.request_id ||
(id !== undefined && id !== event.sequence) ||
event.sequence <= lastSequence) {
throw new TypeError("Offer Search stream event sequence or type is invalid");
}
if (event.type === "candidate_provisional") {
if (streamRequestDigest !== undefined &&
event.details.request_digest !== streamRequestDigest) {
throw new TypeError("Offer Search provisional candidate request binding changed");
}
streamRequestDigest = event.details.request_digest;
}
lastSequence = event.sequence;
return event;
};
while (true) {
const chunk = await reader.read();
buffer =
`${buffer}${decoder.decode(chunk.value, { stream: !chunk.done })}`.replaceAll("\r\n", "\n");
let boundary = buffer.indexOf("\n\n");
while (boundary >= 0) {
const frame = buffer.slice(0, boundary);
buffer = buffer.slice(boundary + 2);
const event = consumeFrame(frame);
if (event)
yield event;
if (finalResult)
return finalResult;
boundary = buffer.indexOf("\n\n");
}
if (chunk.done)
break;
}
if (buffer.trim().length > 0) {
const event = consumeFrame(buffer);
if (event)
yield event;
if (finalResult)
return finalResult;
}
throw attachIdempotencyKey(new TypeError("Offer Search stream ended before its final result"), idempotencyKey);
}
finally {
await reader?.cancel().catch(() => undefined);
request.cleanup();
}
}
/** Re-read one persisted offer generation at the exact action boundary. This final fence always
* returns REVIEW with commerce permission withheld; it never authorizes quoting or purchasing. */
async gateOfferSearch(input, options) {
const result = await this.post("/v1/search-offers/gate", input, options);
return reviewOnlyCommerceActionTimeGateResult(result, input);
}
/** Build, sign, and persist a complete action-bound proof packet. */

@@ -211,0 +400,0 @@ audit(input, options) {

+4
-2
{
"name": "@usekaval/kaval",
"version": "0.3.1",
"version": "0.4.0",
"license": "Apache-2.0",
"description": "Action-bound verification for AI agents — signed proof packets plus ALLOW/BLOCK/REVIEW gates.",
"description": "Evidence gates for AI agents: review-only offer research and action-bound ALLOW/REVIEW/BLOCK decisions.",
"type": "module",

@@ -22,2 +22,4 @@ "main": "./dist/index.js",

"agents",
"evidence",
"commerce",
"freshness",

@@ -24,0 +26,0 @@ "rag",

+147
-6
# @usekaval/kaval
The freshness gate for AI. Give kaval a belief your system already holds — a cached fact, a CRM
field, an agent memory — and it checks the live world and returns a typed verdict: `current`,
`stale`, `contradicted`, `unsupported`, `conflicting`, or `insufficient`.
The evidence gate for AI agents. Before an agent acts, Kaval checks that the current evidence still
supports that exact action. The full proof lifecycle returns `ALLOW`, `REVIEW`, or `BLOCK`; when the
evidence changes or expires, the permission does too.
**Search retrieves evidence. Kaval decides whether that evidence is sufficient for the action.**
```bash

@@ -24,2 +26,140 @@ npm install @usekaval/kaval

## Find current offer evidence (review-only)
```ts
import { Kaval, type OfferSearchInput } from "@usekaval/kaval";
const request: OfferSearchInput = {
schema_revision: 1,
request_id: crypto.randomUUID(),
raw_description: "Makita XPH14Z hammer drill, tool only",
target: {
schema_revision: 1,
name: "Makita XPH14Z",
identifiers: [{ scheme: "model", value: "XPH14Z" }],
attributes: [{ key: "kit", value: false }],
},
requested_condition: "new",
destination: { country_code: "US", region: "CA", postal_code: "94107" },
match_policy: {
identity_requirement: "shared_identifier",
required_identifier_schemes: ["model"],
required_attribute_keys: ["kit"],
permitted_substitutions: [],
},
seller_policy: {
allowed_seller_ids: [],
blocked_seller_ids: [],
allowed_kinds: ["brand_direct", "authorized_retailer"],
require_authorized: true,
},
destination_policy: {
require_eligible: true,
require_exact_region: true,
require_exact_postal_code: true,
},
price_policy: {
currency: "USD",
require_complete_landed_total: true,
allow_estimated_components: false,
allow_member_price: false,
allow_subscription_price: false,
allow_coupon_price: false,
allow_installment_display: false,
allow_trade_in_price: false,
},
source_policy: {
allowed_source_ids: [],
blocked_source_ids: [],
require_origin_evidence: true,
},
intended_action: {
description: "Quote this exact item to a customer",
materiality: "high",
reversibility: "partially_reversible",
},
freshness_maximum_age_ms: 300_000,
max_results: 5,
minimum_unique_sellers: 2,
deadline_ms: 15_000,
maximum_cost_micro_usd: 50_000,
maximum_search_calls: 4,
maximum_fetches: 12,
};
const kaval = new Kaval({
apiKey: process.env.KAVAL_API_KEY,
});
const result = await kaval.searchOffers(request);
if (result.action.state === "NEEDS_REVIEW") {
await queueForHumanReview(result.candidates);
}
// When durable lifecycle metadata is present, final-fence the exact generation at action time.
// Even current evidence remains REVIEW-only until commerce authorization is calibrated.
if (result.lifecycle?.persistence === "persisted") {
const finalFence = await kaval.gateOfferSearch({
dependency_id: result.lifecycle.dependency_id,
generation_id: result.lifecycle.generation_id,
generation_number: result.lifecycle.generation_number,
generation_digest: result.lifecycle.generation_digest,
action_binding: result.lifecycle.action_binding,
});
if (finalFence.state !== "current_review_only") {
await refreshOfferEvidence(result.lifecycle.dependency_id);
}
// finalFence.disposition === "REVIEW" and finalFence.permission === "withheld" in every state.
}
```
For progressive UI or agent feedback, consume the same operation as SSE. The last event contains the
same guarded result returned by `searchOffers()`; earlier events are explicitly `research_only` and
cannot authorize a quote or purchase:
```ts
for await (const event of kaval.streamOfferSearch(request, {
idempotencyKey: crypto.randomUUID(),
})) {
if (event.type === "candidate_provisional") {
// Origin verification finished, but final selection and lifecycle persistence have not.
// durable=false, actionable=false, permission="withheld".
renderProvisionalOffer(event.details.candidate);
} else if (event.type === "final") {
await queueForHumanReview(event.result.candidates);
} else {
console.log(
event.type,
event.type === "replay" ? "completed operation replayed" : event.message,
);
}
}
```
`candidate_provisional` is the only pre-completion candidate event. Its typed details always state
`publication_state: "provisional"`, `durable: false`, `actionable: false`,
`permission: "withheld"`, and `final_inclusion: "not_yet_determined"`. The SDK binds its request
ID and cryptographic digest across provisional, replay, and terminal results and rejects drift. The
later `candidate` event has crossed the current final publication boundary; only the exact
`lifecycle.selected_candidate_id` is durable, and every candidate remains review-only.
Offer Search researches the accessible configured web through configured structured source workers,
search discovery, direct origin re-fetches, serialized-DOM browser fallback, and optional
destination-aware checkout resolution. `candidate.checkout` contains the checkout receipt when one
was verified; `acquisition.source_ledger` states which planned sources succeeded, failed, were
prohibited, or remained unsearched. Coverage is explicitly bounded, not a claim to have searched the
literal entire internet. Its public output is deliberately shadow-grade: `action.state` is
`NEEDS_REVIEW` or `NO_RELIABLE_OFFER`, candidate dispositions are `review` or `rejected`, and the
SDK rejects any drifted response that claims `ALLOW`, `BLOCK`, `SAFE_TO_QUOTE`, or other commerce
authority. Do not quote or purchase from this result without review. `searchOffers()` accepts the same
`{ idempotencyKey?, signal?, timeoutMs? }` request options as other billable calls;
`streamOfferSearch()` also closes the response stream when its signal is aborted or iteration stops.
When the server has a durable commerce lifecycle configured, `result.lifecycle` identifies the
immutable evidence generation, exact selected candidate, and action binding. Call
`gateOfferSearch()` immediately before the action boundary. It re-reads that generation and the
latest stream head, but deliberately returns only `disposition: "REVIEW"` and
`permission: "withheld"`; stale, expired, invalidated, changed, revoked, unavailable, or mismatched
evidence must be refreshed or reviewed.
## Build a proof, then gate the action

@@ -72,3 +212,3 @@

## Gate a belief before you act on it
## Legacy held-belief compatibility

@@ -86,3 +226,4 @@ ```ts

`verify()` returns the verdict plus `act` — `true` only when the belief is `current` and confident
`verify()` preserves the original currentness API. It returns the verdict plus `act` — `true` only
when the belief is `current` and confident
(≥ 0.7 by default; override with `minConfidence`).

@@ -148,3 +289,3 @@

`audit` · `gateAction` (`gate` alias) · `verify` · `check` · `extractAndCheck` · `scanStore` ·
`searchOffers` · `streamOfferSearch` · `gateOfferSearch` · `audit` · `gateAction` (`gate` alias) · `verify` · `check` · `extractAndCheck` · `scanStore` ·
`monitor` · `reportOutcome` · `kaval` · `kavalBatch` · `health`. Billable methods accept a final

@@ -151,0 +292,0 @@ `{ idempotencyKey?, signal?, timeoutMs? }` request-options argument (`kavalBatch` includes it alongside