pivotick - v2.0.1
    Preparing search index...

    Interface PivotDefinition

    One runnable enrichment: what it is called, what it runs on, how to advertise what is out there and how to fetch it.

    A pivot is two functions and some metadata. PivotDefinition.summarize is the cheap "what's out there" call whose facets become the narrowing controls; PivotDefinition.fetch is the real one. Results are candidates — staged for triage, never on the canvas — unless the pivot declares PivotDefinition.autoIngest.

    interface PivotDefinition {
        appliesTo?: (nodes: Node[]) => boolean | Node[];
        autoIngest?: boolean;
        autoSave?: boolean;
        fetch: (
            nodes: Node[],
            narrowing: PivotNarrowing,
            ctx: PivotContext,
        ) => PivotResult | Promise<PivotResult>;
        icon?: string;
        id: string;
        label: string;
        maxCandidates?: number;
        origin?: "none" | "selection";
        save?: (
            payload: PivotSavePayload,
            ctx: PivotSaveContext,
        ) => PivotSaveOutcome | Promise<PivotSaveOutcome>;
        summarize?: (
            nodes: Node[],
            narrowing: PivotNarrowing,
            ctx: PivotContext,
        ) => PivotSummary | Promise<PivotSummary>;
    }
    Index

    Properties

    appliesTo?: (nodes: Node[]) => boolean | Node[]

    Whether this pivot applies to a given origin, and to how much of it. Re-read on every origin change, so it must be synchronous and cheap. Omit it and the pivot applies to everything. Not consulted when origin is 'none'.

    Return a boolean for a rule about the origin as a whole — "only with two or more picked", "never on a note". Return the nodes it applies to for a rule that reads one node at a time, which is the normal case for enrichment: a selection mixing a domain and an IP still offers the domain-only providers, against the domain alone. An empty array means the same as false.

    Whatever it keeps is the origin the provider is called with — summarize and fetch never see a node this turned down.

    appliesTo: nodes => nodes.length >= 2                          // whole origin
    appliesTo: nodes => nodes.filter(n => accepted.has(typeOf(n))) // per node
    autoIngest?: boolean

    Land results directly instead of staging them for triage. For small, trusted results — expanding an event into its objects — not for anything an analyst would want to pick through. The cap still applies.

    true and false are both answers, and both hold however the run was started. Leaving it unset is not the same as false: it says the pivot has no view, so a one-click run may decide on size alone — see PivotRunOptions.autoIngestUpTo. Runs made any other way still stage.

    undefined — stages, unless the run itself sets a size to land under
    
    autoSave?: boolean

    Write each run the moment it lands, with no gesture. For a pivot whose results are the source system's own data already — expanding an event into its objects — where saving is an update rather than a decision.

    The save runs after the ingest resolves rather than inside it, so a slow backend never holds up the canvas; its outcome is reported by the notifier.

    false
    
    fetch: (
        nodes: Node[],
        narrowing: PivotNarrowing,
        ctx: PivotContext,
    ) => PivotResult | Promise<PivotResult>

    The real fetch, narrowed by what the analyst chose.

    icon?: string

    SVG string, injected with innerHTML and not sanitised — it must be trusted.

    id: string

    Stable identity: what the registry keys on, and the provenance tag written on ingest.

    label: string

    Label, used verbatim (so it can be translated).

    maxCandidates?: number

    Refuse to fetch while the advertised count exceeds this. There is no library default: a pivot that declares no cap is never gated by one (the absolute ceiling of PivotManagerLike.candidateCeiling still applies to what fetch returns).

    origin?: "none" | "selection"

    What this pivot runs on. 'selection' pivots need an origin — the nodes the analyst pointed at; 'none' pivots need no nodes at all (search, import, a staging tray) and receive [].

    'selection'
    
    save?: (
        payload: PivotSavePayload,
        ctx: PivotSaveContext,
    ) => PivotSaveOutcome | Promise<PivotSaveOutcome>

    Write an ingested run's result back to the source system — the one half of the contract that is not read-only.

    Omit it and this pivot's results are not savable: they never enter the ledger, are never counted unsaved, and no Save appears for them. A pivot over derived data that could not be written anywhere should omit it rather than declare one that fails.

    Never called by the library on its own — an explicit PivotManagerLike.save, or PivotDefinition.autoSave. The consumer performs the write; the library only asks for it and records the answer.

    summarize?: (
        nodes: Node[],
        narrowing: PivotNarrowing,
        ctx: PivotContext,
    ) => PivotSummary | Promise<PivotSummary>

    Cheap "what's out there". Called with {} before any narrowing exists, and re-run as the origin or the narrowing changes; its facets become the narrowing controls and its total is the number the cap is judged against.

    Omit it and the pivot offers no advertised count and no narrowing — legal, but then PivotDefinition.fetch must be safe to call blind, since nothing can gate it.