// Types for kaito-push.js — written rather than `@ts-expect-error`'d, same reason as // handover-message.d.ts: this is OUR module and its result is customer-facing. The publish // response carries this object, so a caller that mistakes "skipped" for "pushed" reports a site // as indexed when it is not — which is precisely the failure this module exists to stop. /** One published page, in the shape `/api/kaito/ingest` accepts. */ export interface KaitoDocument { /** Repo-relative path. Stable across edits, so a re-push updates rather than duplicates. */ id: string; /** The address a visitor opens. Without it the document is never indexed (cited-always). */ url: string; title?: string; text: string; lang?: string; /** * Which build of THIS module's extraction logic produced this document — see * `EXTRACTOR_VERSION`. Folded by the receiver into the hash that decides "unchanged, skip", so * a page whose markdown is byte-identical to the last push still re-embeds the day the * extractor itself changes what it derives from that markdown. */ extractorVersion?: string; } /** * What the hand-off did. `pushed:false` ALWAYS carries a `reason` — "KAITO is off for this site", * "the secret is unset" and "the endpoint 401'd" must never be indistinguishable from silence. */ export type KaitoPushResult = | { pushed: true; documents: number; embedded?: number; reused?: number; deleted?: number; /** Pages the index refused. Only the publisher can fix these, so they ride back. */ dropped?: Array<{ id: string; reason: string }>; /** * The caller named an origin and it could not be used, so citations fell back to the site * record's `domain`. Present ONLY when that happened — a silent fallback is how a citation * ends up pointing at somebody else's site with nobody the wiser. */ originIgnored?: string; } | { pushed: false; reason: string; detail?: string; /** * 🔴 THE INGEST WAS ALREADY UNDER WAY WHEN THIS FAILED (R2-P2-2). Batched ingest fails by * RETURNING, so this is how a caller tells 「part 9 of 13 came back 524, and the first eight * parts are on the bill」 from 「we never asked」. Absent means nothing was spent and a * reindex slot may be handed straight back; present means the spend ceiling has to hold or * it is not a ceiling. */ started?: boolean; /** Which batch, out of how many — the size of the corpus is usually the problem. */ failedPart?: string; }; export interface KaitoPushOptions { /** Origin of the feelreef deployment that hosts `/api/kaito/ingest`. */ base?: string; /** Shared secret; both sides must carry the same one or the endpoint fail-closes. */ secret?: string; /** * Where this build is ACTUALLY served from — the caller knows, this module cannot. * * 🔴 Not the site record's `domain`: that is where the site is GOING, and until it cuts over the * name still belongs to the owner's current host. Not a per-deployment * `https://..pages.dev` either — correct today, orphaned by the next publish. * `resolveCitationOrigin` refuses both wrong shapes and says which. */ origin?: string; /** * The Worker env, read for MODULE_GATES_ENABLED only. Absent keeps the `kaito` gate ON — a * caller that cannot show the switch cannot be told the gate is off, and refusing an unpaid * push is the conservative half of that. Present-but-unreadable throws. */ env?: { MODULE_GATES_ENABLED?: string }; fetchFn?: typeof fetch; } /** * Which address a site's passages should be cited at. `domain` counts as a LOCATION only when the * site also has a prod project (`canPublish`); otherwise it is where the site is going, and the * Pages project alias is the only honest answer. */ export function siteCitationOrigin(where?: { domain?: string; canPublish?: boolean; project?: string; }): string | undefined; /** Vet an origin for use in citations. `{}` means the caller supplied nothing, which is not a * rejection; `{ why }` is a rejection with its reason. */ export function resolveCitationOrigin(candidate?: string | null): { origin?: string; why?: string }; /** Prose only: frontmatter and `%% sitetile: … %%` layout sentinels removed. */ export function irBodyText(md: string): string; /** * The seams a corpus read needs. * * 🏛 `kaitoCorpus` IS OPTIONAL AND ITS ABSENCE IS A REAL CASE, not a degraded one (owner ruling 38, * CANON-where-values-live.md 第一條). It is the platform's answer to 「what may KAITO index here」, * which outranks the `ir/_site.md` mirror; a caller with no platform to ask — the operator's hand * push, the stdio package running against somebody's own checkout, an ejected site — simply reads * the mirror, which is what the mirror is FOR. */ export interface KaitoCorpusDeps { store: { list(site: unknown): Promise; read(site: unknown, rel: string): Promise }; kaitoCorpus?: { get(): Promise }; } export function collectSiteDocuments( site: { key: string; domain?: string; irDir?: string }, deps: KaitoCorpusDeps, opts?: { origin?: string }, ): Promise; /** Never throws into the publish path: a corpus that failed to land must not un-publish a site. */ export function pushCorpusToKaito( // `ref` is which commit the store reads through — pinned to the SERVED version by the // `set_site_option` reindex (像素眼 P1-2), and left to the store's own default everywhere else. site: { key: string; domain?: string; irDir?: string; modules?: string[]; ref?: string }, deps: KaitoCorpusDeps, opts?: KaitoPushOptions, ): Promise; /** * Push one card's words. A card has no publish step, so `save_card` is the moment. * A row with no module list is treated as KAITO-OFF — never as "probably on". */ export function pushCardToKaito( row: { handle: string; modules?: string[] }, markdown: string, opts?: KaitoPushOptions & { url?: string }, ): Promise;