@aigne/afs-index 1.12.0-beta.5
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/LICENSE.md +26 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/backend/d1-index-backend.cjs +656 -0
- package/dist/backend/d1-index-backend.d.cts +149 -0
- package/dist/backend/d1-index-backend.d.cts.map +1 -0
- package/dist/backend/d1-index-backend.d.mts +149 -0
- package/dist/backend/d1-index-backend.d.mts.map +1 -0
- package/dist/backend/d1-index-backend.mjs +657 -0
- package/dist/backend/d1-index-backend.mjs.map +1 -0
- package/dist/backend/d1-vector-backend.cjs +83 -0
- package/dist/backend/d1-vector-backend.d.cts +21 -0
- package/dist/backend/d1-vector-backend.d.cts.map +1 -0
- package/dist/backend/d1-vector-backend.d.mts +21 -0
- package/dist/backend/d1-vector-backend.d.mts.map +1 -0
- package/dist/backend/d1-vector-backend.mjs +84 -0
- package/dist/backend/d1-vector-backend.mjs.map +1 -0
- package/dist/backend/memory-backend.cjs +304 -0
- package/dist/backend/memory-backend.d.cts +66 -0
- package/dist/backend/memory-backend.d.cts.map +1 -0
- package/dist/backend/memory-backend.d.mts +66 -0
- package/dist/backend/memory-backend.d.mts.map +1 -0
- package/dist/backend/memory-backend.mjs +305 -0
- package/dist/backend/memory-backend.mjs.map +1 -0
- package/dist/backend/prefix-range.cjs +25 -0
- package/dist/backend/prefix-range.mjs +25 -0
- package/dist/backend/prefix-range.mjs.map +1 -0
- package/dist/backend/schema.cjs +187 -0
- package/dist/backend/schema.mjs +188 -0
- package/dist/backend/schema.mjs.map +1 -0
- package/dist/backend/sqlite-backend.cjs +889 -0
- package/dist/backend/sqlite-backend.d.cts +96 -0
- package/dist/backend/sqlite-backend.d.cts.map +1 -0
- package/dist/backend/sqlite-backend.d.mts +96 -0
- package/dist/backend/sqlite-backend.d.mts.map +1 -0
- package/dist/backend/sqlite-backend.mjs +890 -0
- package/dist/backend/sqlite-backend.mjs.map +1 -0
- package/dist/backend/types.d.cts +209 -0
- package/dist/backend/types.d.cts.map +1 -0
- package/dist/backend/types.d.mts +209 -0
- package/dist/backend/types.d.mts.map +1 -0
- package/dist/backend/upstash-vector-backend.cjs +98 -0
- package/dist/backend/upstash-vector-backend.d.cts +21 -0
- package/dist/backend/upstash-vector-backend.d.cts.map +1 -0
- package/dist/backend/upstash-vector-backend.d.mts +21 -0
- package/dist/backend/upstash-vector-backend.d.mts.map +1 -0
- package/dist/backend/upstash-vector-backend.mjs +98 -0
- package/dist/backend/upstash-vector-backend.mjs.map +1 -0
- package/dist/backend/vector-backend.d.cts +29 -0
- package/dist/backend/vector-backend.d.cts.map +1 -0
- package/dist/backend/vector-backend.d.mts +29 -0
- package/dist/backend/vector-backend.d.mts.map +1 -0
- package/dist/dirty-queue.d.cts +41 -0
- package/dist/dirty-queue.d.cts.map +1 -0
- package/dist/dirty-queue.d.mts +41 -0
- package/dist/dirty-queue.d.mts.map +1 -0
- package/dist/embed.cjs +45 -0
- package/dist/embed.d.cts +20 -0
- package/dist/embed.d.cts.map +1 -0
- package/dist/embed.d.mts +20 -0
- package/dist/embed.d.mts.map +1 -0
- package/dist/embed.mjs +46 -0
- package/dist/embed.mjs.map +1 -0
- package/dist/extraction/defaults.cjs +242 -0
- package/dist/extraction/defaults.d.cts +14 -0
- package/dist/extraction/defaults.d.cts.map +1 -0
- package/dist/extraction/defaults.d.mts +14 -0
- package/dist/extraction/defaults.d.mts.map +1 -0
- package/dist/extraction/defaults.mjs +242 -0
- package/dist/extraction/defaults.mjs.map +1 -0
- package/dist/extraction/field-map.cjs +162 -0
- package/dist/extraction/field-map.d.cts +70 -0
- package/dist/extraction/field-map.d.cts.map +1 -0
- package/dist/extraction/field-map.d.mts +70 -0
- package/dist/extraction/field-map.d.mts.map +1 -0
- package/dist/extraction/field-map.mjs +157 -0
- package/dist/extraction/field-map.mjs.map +1 -0
- package/dist/extraction/manager.cjs +74 -0
- package/dist/extraction/manager.d.cts +47 -0
- package/dist/extraction/manager.d.cts.map +1 -0
- package/dist/extraction/manager.d.mts +47 -0
- package/dist/extraction/manager.d.mts.map +1 -0
- package/dist/extraction/manager.mjs +74 -0
- package/dist/extraction/manager.mjs.map +1 -0
- package/dist/extraction/path-anchors.cjs +86 -0
- package/dist/extraction/path-anchors.d.cts +72 -0
- package/dist/extraction/path-anchors.d.cts.map +1 -0
- package/dist/extraction/path-anchors.d.mts +72 -0
- package/dist/extraction/path-anchors.d.mts.map +1 -0
- package/dist/extraction/path-anchors.mjs +86 -0
- package/dist/extraction/path-anchors.mjs.map +1 -0
- package/dist/follower-scheduler.cjs +92 -0
- package/dist/follower-scheduler.d.cts +58 -0
- package/dist/follower-scheduler.d.cts.map +1 -0
- package/dist/follower-scheduler.d.mts +58 -0
- package/dist/follower-scheduler.d.mts.map +1 -0
- package/dist/follower-scheduler.mjs +92 -0
- package/dist/follower-scheduler.mjs.map +1 -0
- package/dist/follower.cjs +577 -0
- package/dist/follower.d.cts +241 -0
- package/dist/follower.d.cts.map +1 -0
- package/dist/follower.d.mts +241 -0
- package/dist/follower.d.mts.map +1 -0
- package/dist/follower.mjs +571 -0
- package/dist/follower.mjs.map +1 -0
- package/dist/index-provider.cjs +1166 -0
- package/dist/index-provider.d.cts +175 -0
- package/dist/index-provider.d.cts.map +1 -0
- package/dist/index-provider.d.mts +175 -0
- package/dist/index-provider.d.mts.map +1 -0
- package/dist/index-provider.mjs +1167 -0
- package/dist/index-provider.mjs.map +1 -0
- package/dist/index.cjs +53 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.mts +22 -0
- package/dist/index.mjs +20 -0
- package/dist/keys/exact.cjs +20 -0
- package/dist/keys/exact.mjs +20 -0
- package/dist/keys/exact.mjs.map +1 -0
- package/dist/keys/location.cjs +13 -0
- package/dist/keys/location.mjs +13 -0
- package/dist/keys/location.mjs.map +1 -0
- package/dist/keys/normalized.cjs +62 -0
- package/dist/keys/normalized.mjs +63 -0
- package/dist/keys/normalized.mjs.map +1 -0
- package/dist/keys/person.cjs +15 -0
- package/dist/keys/person.mjs +15 -0
- package/dist/keys/person.mjs.map +1 -0
- package/dist/keys/registry.cjs +45 -0
- package/dist/keys/registry.d.cts +15 -0
- package/dist/keys/registry.d.cts.map +1 -0
- package/dist/keys/registry.d.mts +15 -0
- package/dist/keys/registry.d.mts.map +1 -0
- package/dist/keys/registry.mjs +46 -0
- package/dist/keys/registry.mjs.map +1 -0
- package/dist/keys/time.cjs +128 -0
- package/dist/keys/time.mjs +128 -0
- package/dist/keys/time.mjs.map +1 -0
- package/dist/keys/topic.cjs +23 -0
- package/dist/keys/topic.mjs +23 -0
- package/dist/keys/topic.mjs.map +1 -0
- package/dist/manifest-index.cjs +29 -0
- package/dist/manifest-index.d.cts +24 -0
- package/dist/manifest-index.d.cts.map +1 -0
- package/dist/manifest-index.d.mts +24 -0
- package/dist/manifest-index.d.mts.map +1 -0
- package/dist/manifest-index.mjs +28 -0
- package/dist/manifest-index.mjs.map +1 -0
- package/dist/offline-rebuild.cjs +48 -0
- package/dist/offline-rebuild.d.cts +57 -0
- package/dist/offline-rebuild.d.cts.map +1 -0
- package/dist/offline-rebuild.d.mts +57 -0
- package/dist/offline-rebuild.d.mts.map +1 -0
- package/dist/offline-rebuild.mjs +49 -0
- package/dist/offline-rebuild.mjs.map +1 -0
- package/dist/query/engine.cjs +433 -0
- package/dist/query/engine.d.cts +34 -0
- package/dist/query/engine.d.cts.map +1 -0
- package/dist/query/engine.d.mts +34 -0
- package/dist/query/engine.d.mts.map +1 -0
- package/dist/query/engine.mjs +433 -0
- package/dist/query/engine.mjs.map +1 -0
- package/dist/query/limits.cjs +12 -0
- package/dist/query/limits.mjs +12 -0
- package/dist/query/limits.mjs.map +1 -0
- package/dist/text/cjk.cjs +30 -0
- package/dist/text/cjk.d.cts +24 -0
- package/dist/text/cjk.d.cts.map +1 -0
- package/dist/text/cjk.d.mts +24 -0
- package/dist/text/cjk.d.mts.map +1 -0
- package/dist/text/cjk.mjs +30 -0
- package/dist/text/cjk.mjs.map +1 -0
- package/dist/text/fts.cjs +244 -0
- package/dist/text/fts.mjs +245 -0
- package/dist/text/fts.mjs.map +1 -0
- package/dist/text/host.cjs +39 -0
- package/dist/text/host.mjs +38 -0
- package/dist/text/host.mjs.map +1 -0
- package/dist/types.cjs +44 -0
- package/dist/types.d.cts +393 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +393 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +42 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { IndexBackend } from "./backend/types.cjs";
|
|
2
|
+
import { DirtyPathQueue } from "./dirty-queue.cjs";
|
|
3
|
+
import { AFSRoot, BlockletIndexDomain } from "@aigne/afs";
|
|
4
|
+
|
|
5
|
+
//#region src/follower.d.ts
|
|
6
|
+
declare const FOLLOWER_CONSUMER_ID = "index";
|
|
7
|
+
/**
|
|
8
|
+
* Derive a follower consumer_id that isolates per `(scope, instanceDid)` —
|
|
9
|
+
* `"index:{scope}:{instanceDid}"`. A single shared backend (Node's `/user/index`
|
|
10
|
+
* file, CF's D1) hosts many callers AND many blocklets per caller; the cursor
|
|
11
|
+
* row must be unique per (caller scope × blocklet instance) because each
|
|
12
|
+
* blocklet follows its OWN instance-space changelog. `instanceDid` is optional
|
|
13
|
+
* for backward compatibility (bare `index:{scope}` for pre-fix rows / callers
|
|
14
|
+
* that don't supply it); passing the bare `FOLLOWER_CONSUMER_ID` is only safe
|
|
15
|
+
* for single-scope callers (tests, standalone use).
|
|
16
|
+
*/
|
|
17
|
+
declare function deriveFollowerConsumerId(scope: string, instanceDid?: string | null): string;
|
|
18
|
+
/**
|
|
19
|
+
* Memory-map key for a caller's per-blocklet index resources (the AFSIndex
|
|
20
|
+
* handle, its in-flight build promise, its IndexFollower). Isolation is
|
|
21
|
+
* per-`(scope, instanceDid)`: the SAME caller (scope) gets a SEPARATE index per
|
|
22
|
+
* blocklet (instanceDid). Keying these isolate-lived maps by scope ALONE let a
|
|
23
|
+
* caller's second index-blocklet reuse the FIRST's handle/follower (wrong bound
|
|
24
|
+
* domains + wrong instance-space changelog) — the in-memory twin of the cursor
|
|
25
|
+
* collision `deriveFollowerConsumerId` guards against.
|
|
26
|
+
*/
|
|
27
|
+
declare function userIndexKey(scope: string, instanceDid?: string | null): string;
|
|
28
|
+
declare const DEFAULT_MAX_PROCESSED_PER_TICK = 4;
|
|
29
|
+
declare const DEFAULT_MAX_NOOP_PER_TICK = 12;
|
|
30
|
+
declare const DEFAULT_MAX_SCAN_PER_TICK = 400;
|
|
31
|
+
/** Preferred alias for {@link DEFAULT_MAX_SCAN_PER_TICK} in dirty-drain call sites. */
|
|
32
|
+
declare const DEFAULT_MAX_DIRTY_ROWS_PER_TICK = 400;
|
|
33
|
+
interface IndexFollowerBatchResult {
|
|
34
|
+
scanned: number;
|
|
35
|
+
/** Matched PUT rows that consumed the expensive maxProcessed budget. */
|
|
36
|
+
processed: number;
|
|
37
|
+
/**
|
|
38
|
+
* Rows that consumed the maxNoop budget (design §8): delete rows, put-rows
|
|
39
|
+
* whose live state was missing (removed as cleanup), AND non-indexable
|
|
40
|
+
* (unmatched-domain) rows.
|
|
41
|
+
*/
|
|
42
|
+
noopProcessed: number;
|
|
43
|
+
/** PUT rows that actually wrote entry/anchor/summary index data. */
|
|
44
|
+
indexed: number;
|
|
45
|
+
/** Delete/remove rows whose index cleanup was attempted. */
|
|
46
|
+
deleted: number;
|
|
47
|
+
/** Matched rows that intentionally wrote no index data (empty or stale content). */
|
|
48
|
+
nooped: number;
|
|
49
|
+
advanced: boolean;
|
|
50
|
+
hasMore: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* At least one dirty row lost the ack race-guard this tick — a newer write
|
|
53
|
+
* bumped `latest_seq` while we processed, so the guarded ack no-oped and the
|
|
54
|
+
* newer dirty row waits for the next tick. NOT an error (real progress was
|
|
55
|
+
* made on the superseded state); surfaced so the CF/Node drain logs can
|
|
56
|
+
* distinguish healthy churn (`ackRace`) from failures (`failed`).
|
|
57
|
+
*/
|
|
58
|
+
ackRace: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Why the tick stopped. `scan_budget` = the dirty-row FETCH budget (maxScan /
|
|
61
|
+
* maxDirtyRows) was exhausted — the name predates the §13 cutover (it used to
|
|
62
|
+
* mean "changelog scan budget"); kept as a stable value across the exported
|
|
63
|
+
* scheduler/daemon types.
|
|
64
|
+
*/
|
|
65
|
+
stopReason?: "processed_budget" | "noop_budget" | "scan_budget" | "exhausted" | "aborted";
|
|
66
|
+
/** Log-compat only; dirty mode never advances a seq cursor (both 0). */
|
|
67
|
+
fromSeq: number;
|
|
68
|
+
toSeq: number;
|
|
69
|
+
matched: number;
|
|
70
|
+
unmatched: number;
|
|
71
|
+
skipped: number;
|
|
72
|
+
failed: number;
|
|
73
|
+
aborted: boolean;
|
|
74
|
+
abortReason?: string;
|
|
75
|
+
}
|
|
76
|
+
interface IndexFollowerOptions {
|
|
77
|
+
/** AFS backed by DIDSpaceProvider+PrefixedTreeIndex — CURRENT-state file read/stat
|
|
78
|
+
* for the dirty drain (the `.changelog` consumption line was deleted at §13 cutover). */
|
|
79
|
+
spaceAfs: AFSRoot;
|
|
80
|
+
/** Index backend for writing indexed data. Must implement cursor methods. */
|
|
81
|
+
backend: IndexBackend;
|
|
82
|
+
/** Domain declarations from blocklet.yaml `index:` section. */
|
|
83
|
+
domains: BlockletIndexDomain[];
|
|
84
|
+
/**
|
|
85
|
+
* Cursor row identity for THIS follower. Defaults to the bare
|
|
86
|
+
* `FOLLOWER_CONSUMER_ID` ("index") for single-scope callers (tests,
|
|
87
|
+
* standalone use). Any caller whose backend hosts MULTIPLE scopes MUST pass
|
|
88
|
+
* `deriveFollowerConsumerId(scope)` — otherwise every scope sharing that
|
|
89
|
+
* backend would read/write the SAME `idx_index_cursor` row, each run
|
|
90
|
+
* clobbering the others' progress.
|
|
91
|
+
*/
|
|
92
|
+
consumerId?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Optional passage embedder — generates the vector stored alongside each
|
|
95
|
+
* indexed summary for semantic recall (Epic #932). Usually left unset here and
|
|
96
|
+
* wired later via `setEmbedder` (see its doc). Returns null to skip embedding.
|
|
97
|
+
*/
|
|
98
|
+
embed?: (text: string) => Promise<number[] | null>;
|
|
99
|
+
/**
|
|
100
|
+
* Source-side dirty queue (index-follower-dirty-path). The follower DRAINS the
|
|
101
|
+
* merged `ds_dirty_path` projection — catch-up is O(unique dirty paths), not
|
|
102
|
+
* O(changelog rows). This is the SOLE catch-up mechanism (§13 cutover — the
|
|
103
|
+
* changelog `/.changelog` replay was deleted); a follower with no dirty queue
|
|
104
|
+
* has no source to drain and `runCatchUp`/`runBatch` are no-ops for it.
|
|
105
|
+
* Normally a fragment-scoped `PrefixedTreeIndex` so `listDirtyPaths` returns
|
|
106
|
+
* stripped `originalPath`s. ack/fail must be a runtime-internal capability,
|
|
107
|
+
* never a public `/user` action.
|
|
108
|
+
*/
|
|
109
|
+
dirtyQueue?: DirtyPathQueue;
|
|
110
|
+
}
|
|
111
|
+
declare class IndexFollower {
|
|
112
|
+
private readonly spaceAfs;
|
|
113
|
+
private readonly backend;
|
|
114
|
+
private readonly domains;
|
|
115
|
+
private readonly consumerId;
|
|
116
|
+
private embed?;
|
|
117
|
+
private catchUpLimits?;
|
|
118
|
+
private readonly dirtyQueue?;
|
|
119
|
+
constructor(opts: IndexFollowerOptions);
|
|
120
|
+
/**
|
|
121
|
+
* Override the inline `runCatchUp()` budget — the per-invocation caps on
|
|
122
|
+
* matched PUT attempts, matched delete/remove rows, and dirty rows FETCHED
|
|
123
|
+
* (`maxScan`). Injected by the runtime from the SAME env group the cron uses
|
|
124
|
+
* (`AFS_INDEX_MAX_*_PER_TICK`) so both indexing paths share one budget group.
|
|
125
|
+
* Unset → provider defaults (standalone/tests).
|
|
126
|
+
*/
|
|
127
|
+
setCatchUpLimits(limits: {
|
|
128
|
+
maxProcessed: number;
|
|
129
|
+
maxNoop?: number;
|
|
130
|
+
maxScan: number;
|
|
131
|
+
}): void;
|
|
132
|
+
/**
|
|
133
|
+
* Wire (or replace) the passage embedder used at index time — semantic recall
|
|
134
|
+
* (Epic #932). Called by `AFSIndex.setFollower` (query-path follower) and by
|
|
135
|
+
* `rebuildFollowerFromCursor` (CF cron-path follower) so BOTH indexing paths
|
|
136
|
+
* write embeddings; without this a changelog-indexed entry has only FTS +
|
|
137
|
+
* anchors and cross-lingual / semantic queries can't match it. A no-op
|
|
138
|
+
* embedder (or a backend without `writeEmbedding`) degrades cleanly to
|
|
139
|
+
* FTS+anchor.
|
|
140
|
+
*/
|
|
141
|
+
setEmbedder(embed: (text: string) => Promise<number[] | null>): void;
|
|
142
|
+
/**
|
|
143
|
+
* Lightweight catch-up: drain any ready dirty rows so a query sees a fresh
|
|
144
|
+
* index without waiting for the next cron tick. Called from execQuery.
|
|
145
|
+
*
|
|
146
|
+
* Dirty drain is the SOLE catch-up mechanism (index-follower-dirty-path §13
|
|
147
|
+
* cutover — the changelog `/.changelog` replay was deleted). Freshness = "are
|
|
148
|
+
* there ready dirty rows under my prefix", so there is no `last_seq` probe: a
|
|
149
|
+
* query sees a fresh index by processing whatever dirty paths are pending
|
|
150
|
+
* (design §4.2, §8). A follower with no dirty queue (standalone/legacy) is a
|
|
151
|
+
* no-op here — it has no source to drain.
|
|
152
|
+
*/
|
|
153
|
+
runCatchUp(): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Bounded per-tick drain of the dirty queue — attempt up to `maxProcessed`
|
|
156
|
+
* matched PUT rows, up to `maxNoop` matched delete/remove/noop rows, fetching
|
|
157
|
+
* at most `maxScan` (a.k.a. `maxDirtyRows`) dirty rows. Called from the cron.
|
|
158
|
+
*
|
|
159
|
+
* Dirty drain is the SOLE mechanism (index-follower-dirty-path §13 cutover —
|
|
160
|
+
* changelog replay was deleted). A follower with no dirty queue has no source
|
|
161
|
+
* to drain, so it is idle. Separate budgets are intentional: matched PUT rows
|
|
162
|
+
* are the expensive read+embed+write axis, delete/noop rows are cheaper.
|
|
163
|
+
*/
|
|
164
|
+
runBatch(limits?: {
|
|
165
|
+
maxProcessed?: number;
|
|
166
|
+
maxNoop?: number; /** Max dirty rows fetched this tick. `maxDirtyRows` is the preferred name. */
|
|
167
|
+
maxScan?: number;
|
|
168
|
+
maxDirtyRows?: number;
|
|
169
|
+
}): Promise<IndexFollowerBatchResult>;
|
|
170
|
+
/** Empty batch result (no dirty queue wired / nothing to drain). */
|
|
171
|
+
private idleResult;
|
|
172
|
+
/**
|
|
173
|
+
* Cold rebuild of an EXPLICIT list of space-relative paths — the enumeration
|
|
174
|
+
* is done by the caller (an external driver listing the live tree via D1),
|
|
175
|
+
* NOT in this process. Reads CURRENT live state per path and writes the
|
|
176
|
+
* derived index layers, independent of any queue — so it is the seam the
|
|
177
|
+
* offline reset-and-rebuild (`offlineRebuildScope`) uses to rebuild from live
|
|
178
|
+
* `ds_entries`. Keeping the per-call cost to just `paths.length`
|
|
179
|
+
* read+embed+writes with ZERO in-Worker tree enumeration is what keeps a small
|
|
180
|
+
* batch inside the CF free-tier per-request CPU/subrequest budget (an in-Worker
|
|
181
|
+
* `maxDepth:-1` enumeration pushed cold isolates over that budget into 503s).
|
|
182
|
+
* Each path is matched against the declared domains and indexed through the
|
|
183
|
+
* same `indexEntry` as the drain path (byte-identical output). `paths` are
|
|
184
|
+
* space-relative, e.g. `"items/foo.json"` (leading slash tolerated).
|
|
185
|
+
*/
|
|
186
|
+
reindexPaths(paths: string[], onProgress?: (done: number, total: number) => void): Promise<{
|
|
187
|
+
indexed: number;
|
|
188
|
+
failed: number;
|
|
189
|
+
skipped: number;
|
|
190
|
+
}>;
|
|
191
|
+
/**
|
|
192
|
+
* Dirty drain (index-follower-dirty-path §8) — the O(unique dirty paths)
|
|
193
|
+
* replacement for changelog replay. Fetches ready dirty rows under this
|
|
194
|
+
* follower's prefix, and for each: domain-matches the stripped `originalPath`,
|
|
195
|
+
* reads CURRENT live state, and indexes / removes accordingly, then acks with
|
|
196
|
+
* the `latestSeq` race guard. A transient failure marks the row with a backoff
|
|
197
|
+
* (so a poison row can't refill the tick) instead of acking.
|
|
198
|
+
*
|
|
199
|
+
* Dirty mode NEVER writes `idx_index_cursor.last_seq` (design §4.2 — it is a
|
|
200
|
+
* dead column post-cutover); scheduling reads `advanced/hasMore/scanned` +
|
|
201
|
+
* the dirty count. The `dirtyQueue.listDirtyPaths({ prefix: "" })` call assumes
|
|
202
|
+
* a fragment-scoped queue (PrefixedTreeIndex), so `row.path` is already the
|
|
203
|
+
* stripped `originalPath` the domain globs + `spaceAfs.read` expect.
|
|
204
|
+
*/
|
|
205
|
+
private processDirty;
|
|
206
|
+
/** Remove the indexed doc(s) for a delete/removed dirty row across matched domains. */
|
|
207
|
+
private removeDirty;
|
|
208
|
+
/** Shared index-removal (delete branch) — throws ChangelogAbortError on failure so the row backs off. */
|
|
209
|
+
private removeIndexed;
|
|
210
|
+
/**
|
|
211
|
+
* Handle a `put` dirty row against CURRENT live state (design §4.3 / §8 step 6):
|
|
212
|
+
* - live exists → indexEntry (writes FTS/anchor/summary/embedding).
|
|
213
|
+
* - live missing (authoritative 404) → remove the indexed doc.
|
|
214
|
+
* - stat throws a NON-404 error → transient → ChangelogAbortError (retry).
|
|
215
|
+
* This is what makes a stale put whose file was deleted converge to "removed",
|
|
216
|
+
* while a replica-lag / D1 blip is NEVER mistaken for a deletion.
|
|
217
|
+
*/
|
|
218
|
+
private indexPutDirty;
|
|
219
|
+
/**
|
|
220
|
+
* Does `originalPath` STILL EXIST (via `stat`)? Used to classify a `read()`
|
|
221
|
+
* failure (issue #935 BLOCK fix #3 / sync-engine parity):
|
|
222
|
+
* - stat 404 (or throws) → the file is gone (later delete, or never existed
|
|
223
|
+
* at this position) → the row is stale, safe to skip.
|
|
224
|
+
* - stat succeeds → the file is live; the read failure was transient (R2/D1
|
|
225
|
+
* blip) and must be retried, not lost.
|
|
226
|
+
* Post-cutover the drain only ever indexes live state (cid is never compared —
|
|
227
|
+
* supersession is caught by the ack race-guard), so existence is the only
|
|
228
|
+
* question left here.
|
|
229
|
+
*/
|
|
230
|
+
private entryStillCurrent;
|
|
231
|
+
private pathMatchesDomain;
|
|
232
|
+
private indexEntry;
|
|
233
|
+
/**
|
|
234
|
+
* Build the stable index entry path for a file. Uses the domain scope
|
|
235
|
+
* (default "/user") as a prefix so query-scope filtering works.
|
|
236
|
+
*/
|
|
237
|
+
private makeEntryPath;
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
export { DEFAULT_MAX_DIRTY_ROWS_PER_TICK, DEFAULT_MAX_NOOP_PER_TICK, DEFAULT_MAX_PROCESSED_PER_TICK, DEFAULT_MAX_SCAN_PER_TICK, FOLLOWER_CONSUMER_ID, IndexFollower, IndexFollowerBatchResult, IndexFollowerOptions, deriveFollowerConsumerId, userIndexKey };
|
|
241
|
+
//# sourceMappingURL=follower.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follower.d.cts","names":[],"sources":["../src/follower.ts"],"mappings":";;;;;cAqDa,oBAAA;;;;;;;;;;;iBAYG,wBAAA,CAAyB,KAAA,UAAe,WAAA;;;;;;;;;;iBAexC,YAAA,CAAa,KAAA,UAAe,WAAA;AAAA,cAe/B,8BAAA;AAAA,cACA,yBAAA;AAAA,cAQA,yBAAA;;cAEA,+BAAA;AAAA,UA+BI,wBAAA;EACf,OAAA;EAkDS;EAhDT,SAAA;EA0Ea;;;;;EApEb,aAAA;EAwCS;EAtCT,OAAA;EAwCS;EAtCT,OAAA;EAqDA;EAnDA,MAAA;EACA,QAAA;EACA,OAAA;EA4Da;;;AAGf;;;;EAvDE,OAAA;EA8GoB;;;;;;EAvGpB,UAAA;EAkDiB;EAhDjB,OAAA;EACA,KAAA;EACA,OAAA;EACA,SAAA;EACA,OAAA;EACA,MAAA;EACA,OAAA;EACA,WAAA;AAAA;AAAA,UAGe,oBAAA;EA+DkC;;EA5DjD,QAAA,EAAU,OAAA;EAyEV;EAvEA,OAAA,EAAS,YAAA;EAuE4B;EArErC,OAAA,EAAS,mBAAA;EAoFH;;;;;;;;EA3EN,UAAA;EAoGY;;;;;EA9FZ,KAAA,IAAS,IAAA,aAAiB,OAAA;EA8IxB;;;;;;;;;;EAnIF,UAAA,GAAa,cAAA;AAAA;AAAA,cAGF,aAAA;EAAA,iBACM,QAAA;EAAA,iBACA,OAAA;EAAA,iBACA,OAAA;EAAA,iBACA,UAAA;EAAA,QACT,KAAA;EAAA,QAGA,aAAA;EAAA,iBACS,UAAA;cAEL,IAAA,EAAM,oBAAA;;;;;;;;EAgBlB,gBAAA,CAAiB,MAAA;IAAU,YAAA;IAAsB,OAAA;IAAkB,OAAA;EAAA;;;;;;;;;;EAanE,WAAA,CAAY,KAAA,GAAQ,IAAA,aAAiB,OAAA;;;;;;;;;;;;EAe/B,UAAA,CAAA,GAAc,OAAA;;;;;;;;;;;EAmBd,QAAA,CAAS,MAAA;IACb,YAAA;IACA,OAAA;IAEA,OAAA;IACA,YAAA;EAAA,IACE,OAAA,CAAQ,wBAAA;;UAUJ,UAAA;;;;;;;;;;;;;;;EAoCF,YAAA,CACJ,KAAA,YACA,UAAA,IAAc,IAAA,UAAc,KAAA,oBAC3B,OAAA;IAAU,OAAA;IAAiB,MAAA;IAAgB,OAAA;EAAA;;;;;;;;;;;;;;;UAwChC,YAAA;;UAwMA,WAAA;;UAUA,aAAA;;;;;;;;;UAyBA,aAAA;;;;;;;;;;;;UAkDA,iBAAA;EAAA,QASN,iBAAA;EAAA,QAKM,UAAA;;;;;UAwHN,aAAA;AAAA"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { IndexBackend } from "./backend/types.mjs";
|
|
2
|
+
import { DirtyPathQueue } from "./dirty-queue.mjs";
|
|
3
|
+
import { AFSRoot, BlockletIndexDomain } from "@aigne/afs";
|
|
4
|
+
|
|
5
|
+
//#region src/follower.d.ts
|
|
6
|
+
declare const FOLLOWER_CONSUMER_ID = "index";
|
|
7
|
+
/**
|
|
8
|
+
* Derive a follower consumer_id that isolates per `(scope, instanceDid)` —
|
|
9
|
+
* `"index:{scope}:{instanceDid}"`. A single shared backend (Node's `/user/index`
|
|
10
|
+
* file, CF's D1) hosts many callers AND many blocklets per caller; the cursor
|
|
11
|
+
* row must be unique per (caller scope × blocklet instance) because each
|
|
12
|
+
* blocklet follows its OWN instance-space changelog. `instanceDid` is optional
|
|
13
|
+
* for backward compatibility (bare `index:{scope}` for pre-fix rows / callers
|
|
14
|
+
* that don't supply it); passing the bare `FOLLOWER_CONSUMER_ID` is only safe
|
|
15
|
+
* for single-scope callers (tests, standalone use).
|
|
16
|
+
*/
|
|
17
|
+
declare function deriveFollowerConsumerId(scope: string, instanceDid?: string | null): string;
|
|
18
|
+
/**
|
|
19
|
+
* Memory-map key for a caller's per-blocklet index resources (the AFSIndex
|
|
20
|
+
* handle, its in-flight build promise, its IndexFollower). Isolation is
|
|
21
|
+
* per-`(scope, instanceDid)`: the SAME caller (scope) gets a SEPARATE index per
|
|
22
|
+
* blocklet (instanceDid). Keying these isolate-lived maps by scope ALONE let a
|
|
23
|
+
* caller's second index-blocklet reuse the FIRST's handle/follower (wrong bound
|
|
24
|
+
* domains + wrong instance-space changelog) — the in-memory twin of the cursor
|
|
25
|
+
* collision `deriveFollowerConsumerId` guards against.
|
|
26
|
+
*/
|
|
27
|
+
declare function userIndexKey(scope: string, instanceDid?: string | null): string;
|
|
28
|
+
declare const DEFAULT_MAX_PROCESSED_PER_TICK = 4;
|
|
29
|
+
declare const DEFAULT_MAX_NOOP_PER_TICK = 12;
|
|
30
|
+
declare const DEFAULT_MAX_SCAN_PER_TICK = 400;
|
|
31
|
+
/** Preferred alias for {@link DEFAULT_MAX_SCAN_PER_TICK} in dirty-drain call sites. */
|
|
32
|
+
declare const DEFAULT_MAX_DIRTY_ROWS_PER_TICK = 400;
|
|
33
|
+
interface IndexFollowerBatchResult {
|
|
34
|
+
scanned: number;
|
|
35
|
+
/** Matched PUT rows that consumed the expensive maxProcessed budget. */
|
|
36
|
+
processed: number;
|
|
37
|
+
/**
|
|
38
|
+
* Rows that consumed the maxNoop budget (design §8): delete rows, put-rows
|
|
39
|
+
* whose live state was missing (removed as cleanup), AND non-indexable
|
|
40
|
+
* (unmatched-domain) rows.
|
|
41
|
+
*/
|
|
42
|
+
noopProcessed: number;
|
|
43
|
+
/** PUT rows that actually wrote entry/anchor/summary index data. */
|
|
44
|
+
indexed: number;
|
|
45
|
+
/** Delete/remove rows whose index cleanup was attempted. */
|
|
46
|
+
deleted: number;
|
|
47
|
+
/** Matched rows that intentionally wrote no index data (empty or stale content). */
|
|
48
|
+
nooped: number;
|
|
49
|
+
advanced: boolean;
|
|
50
|
+
hasMore: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* At least one dirty row lost the ack race-guard this tick — a newer write
|
|
53
|
+
* bumped `latest_seq` while we processed, so the guarded ack no-oped and the
|
|
54
|
+
* newer dirty row waits for the next tick. NOT an error (real progress was
|
|
55
|
+
* made on the superseded state); surfaced so the CF/Node drain logs can
|
|
56
|
+
* distinguish healthy churn (`ackRace`) from failures (`failed`).
|
|
57
|
+
*/
|
|
58
|
+
ackRace: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Why the tick stopped. `scan_budget` = the dirty-row FETCH budget (maxScan /
|
|
61
|
+
* maxDirtyRows) was exhausted — the name predates the §13 cutover (it used to
|
|
62
|
+
* mean "changelog scan budget"); kept as a stable value across the exported
|
|
63
|
+
* scheduler/daemon types.
|
|
64
|
+
*/
|
|
65
|
+
stopReason?: "processed_budget" | "noop_budget" | "scan_budget" | "exhausted" | "aborted";
|
|
66
|
+
/** Log-compat only; dirty mode never advances a seq cursor (both 0). */
|
|
67
|
+
fromSeq: number;
|
|
68
|
+
toSeq: number;
|
|
69
|
+
matched: number;
|
|
70
|
+
unmatched: number;
|
|
71
|
+
skipped: number;
|
|
72
|
+
failed: number;
|
|
73
|
+
aborted: boolean;
|
|
74
|
+
abortReason?: string;
|
|
75
|
+
}
|
|
76
|
+
interface IndexFollowerOptions {
|
|
77
|
+
/** AFS backed by DIDSpaceProvider+PrefixedTreeIndex — CURRENT-state file read/stat
|
|
78
|
+
* for the dirty drain (the `.changelog` consumption line was deleted at §13 cutover). */
|
|
79
|
+
spaceAfs: AFSRoot;
|
|
80
|
+
/** Index backend for writing indexed data. Must implement cursor methods. */
|
|
81
|
+
backend: IndexBackend;
|
|
82
|
+
/** Domain declarations from blocklet.yaml `index:` section. */
|
|
83
|
+
domains: BlockletIndexDomain[];
|
|
84
|
+
/**
|
|
85
|
+
* Cursor row identity for THIS follower. Defaults to the bare
|
|
86
|
+
* `FOLLOWER_CONSUMER_ID` ("index") for single-scope callers (tests,
|
|
87
|
+
* standalone use). Any caller whose backend hosts MULTIPLE scopes MUST pass
|
|
88
|
+
* `deriveFollowerConsumerId(scope)` — otherwise every scope sharing that
|
|
89
|
+
* backend would read/write the SAME `idx_index_cursor` row, each run
|
|
90
|
+
* clobbering the others' progress.
|
|
91
|
+
*/
|
|
92
|
+
consumerId?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Optional passage embedder — generates the vector stored alongside each
|
|
95
|
+
* indexed summary for semantic recall (Epic #932). Usually left unset here and
|
|
96
|
+
* wired later via `setEmbedder` (see its doc). Returns null to skip embedding.
|
|
97
|
+
*/
|
|
98
|
+
embed?: (text: string) => Promise<number[] | null>;
|
|
99
|
+
/**
|
|
100
|
+
* Source-side dirty queue (index-follower-dirty-path). The follower DRAINS the
|
|
101
|
+
* merged `ds_dirty_path` projection — catch-up is O(unique dirty paths), not
|
|
102
|
+
* O(changelog rows). This is the SOLE catch-up mechanism (§13 cutover — the
|
|
103
|
+
* changelog `/.changelog` replay was deleted); a follower with no dirty queue
|
|
104
|
+
* has no source to drain and `runCatchUp`/`runBatch` are no-ops for it.
|
|
105
|
+
* Normally a fragment-scoped `PrefixedTreeIndex` so `listDirtyPaths` returns
|
|
106
|
+
* stripped `originalPath`s. ack/fail must be a runtime-internal capability,
|
|
107
|
+
* never a public `/user` action.
|
|
108
|
+
*/
|
|
109
|
+
dirtyQueue?: DirtyPathQueue;
|
|
110
|
+
}
|
|
111
|
+
declare class IndexFollower {
|
|
112
|
+
private readonly spaceAfs;
|
|
113
|
+
private readonly backend;
|
|
114
|
+
private readonly domains;
|
|
115
|
+
private readonly consumerId;
|
|
116
|
+
private embed?;
|
|
117
|
+
private catchUpLimits?;
|
|
118
|
+
private readonly dirtyQueue?;
|
|
119
|
+
constructor(opts: IndexFollowerOptions);
|
|
120
|
+
/**
|
|
121
|
+
* Override the inline `runCatchUp()` budget — the per-invocation caps on
|
|
122
|
+
* matched PUT attempts, matched delete/remove rows, and dirty rows FETCHED
|
|
123
|
+
* (`maxScan`). Injected by the runtime from the SAME env group the cron uses
|
|
124
|
+
* (`AFS_INDEX_MAX_*_PER_TICK`) so both indexing paths share one budget group.
|
|
125
|
+
* Unset → provider defaults (standalone/tests).
|
|
126
|
+
*/
|
|
127
|
+
setCatchUpLimits(limits: {
|
|
128
|
+
maxProcessed: number;
|
|
129
|
+
maxNoop?: number;
|
|
130
|
+
maxScan: number;
|
|
131
|
+
}): void;
|
|
132
|
+
/**
|
|
133
|
+
* Wire (or replace) the passage embedder used at index time — semantic recall
|
|
134
|
+
* (Epic #932). Called by `AFSIndex.setFollower` (query-path follower) and by
|
|
135
|
+
* `rebuildFollowerFromCursor` (CF cron-path follower) so BOTH indexing paths
|
|
136
|
+
* write embeddings; without this a changelog-indexed entry has only FTS +
|
|
137
|
+
* anchors and cross-lingual / semantic queries can't match it. A no-op
|
|
138
|
+
* embedder (or a backend without `writeEmbedding`) degrades cleanly to
|
|
139
|
+
* FTS+anchor.
|
|
140
|
+
*/
|
|
141
|
+
setEmbedder(embed: (text: string) => Promise<number[] | null>): void;
|
|
142
|
+
/**
|
|
143
|
+
* Lightweight catch-up: drain any ready dirty rows so a query sees a fresh
|
|
144
|
+
* index without waiting for the next cron tick. Called from execQuery.
|
|
145
|
+
*
|
|
146
|
+
* Dirty drain is the SOLE catch-up mechanism (index-follower-dirty-path §13
|
|
147
|
+
* cutover — the changelog `/.changelog` replay was deleted). Freshness = "are
|
|
148
|
+
* there ready dirty rows under my prefix", so there is no `last_seq` probe: a
|
|
149
|
+
* query sees a fresh index by processing whatever dirty paths are pending
|
|
150
|
+
* (design §4.2, §8). A follower with no dirty queue (standalone/legacy) is a
|
|
151
|
+
* no-op here — it has no source to drain.
|
|
152
|
+
*/
|
|
153
|
+
runCatchUp(): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Bounded per-tick drain of the dirty queue — attempt up to `maxProcessed`
|
|
156
|
+
* matched PUT rows, up to `maxNoop` matched delete/remove/noop rows, fetching
|
|
157
|
+
* at most `maxScan` (a.k.a. `maxDirtyRows`) dirty rows. Called from the cron.
|
|
158
|
+
*
|
|
159
|
+
* Dirty drain is the SOLE mechanism (index-follower-dirty-path §13 cutover —
|
|
160
|
+
* changelog replay was deleted). A follower with no dirty queue has no source
|
|
161
|
+
* to drain, so it is idle. Separate budgets are intentional: matched PUT rows
|
|
162
|
+
* are the expensive read+embed+write axis, delete/noop rows are cheaper.
|
|
163
|
+
*/
|
|
164
|
+
runBatch(limits?: {
|
|
165
|
+
maxProcessed?: number;
|
|
166
|
+
maxNoop?: number; /** Max dirty rows fetched this tick. `maxDirtyRows` is the preferred name. */
|
|
167
|
+
maxScan?: number;
|
|
168
|
+
maxDirtyRows?: number;
|
|
169
|
+
}): Promise<IndexFollowerBatchResult>;
|
|
170
|
+
/** Empty batch result (no dirty queue wired / nothing to drain). */
|
|
171
|
+
private idleResult;
|
|
172
|
+
/**
|
|
173
|
+
* Cold rebuild of an EXPLICIT list of space-relative paths — the enumeration
|
|
174
|
+
* is done by the caller (an external driver listing the live tree via D1),
|
|
175
|
+
* NOT in this process. Reads CURRENT live state per path and writes the
|
|
176
|
+
* derived index layers, independent of any queue — so it is the seam the
|
|
177
|
+
* offline reset-and-rebuild (`offlineRebuildScope`) uses to rebuild from live
|
|
178
|
+
* `ds_entries`. Keeping the per-call cost to just `paths.length`
|
|
179
|
+
* read+embed+writes with ZERO in-Worker tree enumeration is what keeps a small
|
|
180
|
+
* batch inside the CF free-tier per-request CPU/subrequest budget (an in-Worker
|
|
181
|
+
* `maxDepth:-1` enumeration pushed cold isolates over that budget into 503s).
|
|
182
|
+
* Each path is matched against the declared domains and indexed through the
|
|
183
|
+
* same `indexEntry` as the drain path (byte-identical output). `paths` are
|
|
184
|
+
* space-relative, e.g. `"items/foo.json"` (leading slash tolerated).
|
|
185
|
+
*/
|
|
186
|
+
reindexPaths(paths: string[], onProgress?: (done: number, total: number) => void): Promise<{
|
|
187
|
+
indexed: number;
|
|
188
|
+
failed: number;
|
|
189
|
+
skipped: number;
|
|
190
|
+
}>;
|
|
191
|
+
/**
|
|
192
|
+
* Dirty drain (index-follower-dirty-path §8) — the O(unique dirty paths)
|
|
193
|
+
* replacement for changelog replay. Fetches ready dirty rows under this
|
|
194
|
+
* follower's prefix, and for each: domain-matches the stripped `originalPath`,
|
|
195
|
+
* reads CURRENT live state, and indexes / removes accordingly, then acks with
|
|
196
|
+
* the `latestSeq` race guard. A transient failure marks the row with a backoff
|
|
197
|
+
* (so a poison row can't refill the tick) instead of acking.
|
|
198
|
+
*
|
|
199
|
+
* Dirty mode NEVER writes `idx_index_cursor.last_seq` (design §4.2 — it is a
|
|
200
|
+
* dead column post-cutover); scheduling reads `advanced/hasMore/scanned` +
|
|
201
|
+
* the dirty count. The `dirtyQueue.listDirtyPaths({ prefix: "" })` call assumes
|
|
202
|
+
* a fragment-scoped queue (PrefixedTreeIndex), so `row.path` is already the
|
|
203
|
+
* stripped `originalPath` the domain globs + `spaceAfs.read` expect.
|
|
204
|
+
*/
|
|
205
|
+
private processDirty;
|
|
206
|
+
/** Remove the indexed doc(s) for a delete/removed dirty row across matched domains. */
|
|
207
|
+
private removeDirty;
|
|
208
|
+
/** Shared index-removal (delete branch) — throws ChangelogAbortError on failure so the row backs off. */
|
|
209
|
+
private removeIndexed;
|
|
210
|
+
/**
|
|
211
|
+
* Handle a `put` dirty row against CURRENT live state (design §4.3 / §8 step 6):
|
|
212
|
+
* - live exists → indexEntry (writes FTS/anchor/summary/embedding).
|
|
213
|
+
* - live missing (authoritative 404) → remove the indexed doc.
|
|
214
|
+
* - stat throws a NON-404 error → transient → ChangelogAbortError (retry).
|
|
215
|
+
* This is what makes a stale put whose file was deleted converge to "removed",
|
|
216
|
+
* while a replica-lag / D1 blip is NEVER mistaken for a deletion.
|
|
217
|
+
*/
|
|
218
|
+
private indexPutDirty;
|
|
219
|
+
/**
|
|
220
|
+
* Does `originalPath` STILL EXIST (via `stat`)? Used to classify a `read()`
|
|
221
|
+
* failure (issue #935 BLOCK fix #3 / sync-engine parity):
|
|
222
|
+
* - stat 404 (or throws) → the file is gone (later delete, or never existed
|
|
223
|
+
* at this position) → the row is stale, safe to skip.
|
|
224
|
+
* - stat succeeds → the file is live; the read failure was transient (R2/D1
|
|
225
|
+
* blip) and must be retried, not lost.
|
|
226
|
+
* Post-cutover the drain only ever indexes live state (cid is never compared —
|
|
227
|
+
* supersession is caught by the ack race-guard), so existence is the only
|
|
228
|
+
* question left here.
|
|
229
|
+
*/
|
|
230
|
+
private entryStillCurrent;
|
|
231
|
+
private pathMatchesDomain;
|
|
232
|
+
private indexEntry;
|
|
233
|
+
/**
|
|
234
|
+
* Build the stable index entry path for a file. Uses the domain scope
|
|
235
|
+
* (default "/user") as a prefix so query-scope filtering works.
|
|
236
|
+
*/
|
|
237
|
+
private makeEntryPath;
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
export { DEFAULT_MAX_DIRTY_ROWS_PER_TICK, DEFAULT_MAX_NOOP_PER_TICK, DEFAULT_MAX_PROCESSED_PER_TICK, DEFAULT_MAX_SCAN_PER_TICK, FOLLOWER_CONSUMER_ID, IndexFollower, IndexFollowerBatchResult, IndexFollowerOptions, deriveFollowerConsumerId, userIndexKey };
|
|
241
|
+
//# sourceMappingURL=follower.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follower.d.mts","names":[],"sources":["../src/follower.ts"],"mappings":";;;;;cAqDa,oBAAA;;;;;;;;;;;iBAYG,wBAAA,CAAyB,KAAA,UAAe,WAAA;;;;;;;;;;iBAexC,YAAA,CAAa,KAAA,UAAe,WAAA;AAAA,cAe/B,8BAAA;AAAA,cACA,yBAAA;AAAA,cAQA,yBAAA;;cAEA,+BAAA;AAAA,UA+BI,wBAAA;EACf,OAAA;EAkDS;EAhDT,SAAA;EA0Ea;;;;;EApEb,aAAA;EAwCS;EAtCT,OAAA;EAwCS;EAtCT,OAAA;EAqDA;EAnDA,MAAA;EACA,QAAA;EACA,OAAA;EA4Da;;;AAGf;;;;EAvDE,OAAA;EA8GoB;;;;;;EAvGpB,UAAA;EAkDiB;EAhDjB,OAAA;EACA,KAAA;EACA,OAAA;EACA,SAAA;EACA,OAAA;EACA,MAAA;EACA,OAAA;EACA,WAAA;AAAA;AAAA,UAGe,oBAAA;EA+DkC;;EA5DjD,QAAA,EAAU,OAAA;EAyEV;EAvEA,OAAA,EAAS,YAAA;EAuE4B;EArErC,OAAA,EAAS,mBAAA;EAoFH;;;;;;;;EA3EN,UAAA;EAoGY;;;;;EA9FZ,KAAA,IAAS,IAAA,aAAiB,OAAA;EA8IxB;;;;;;;;;;EAnIF,UAAA,GAAa,cAAA;AAAA;AAAA,cAGF,aAAA;EAAA,iBACM,QAAA;EAAA,iBACA,OAAA;EAAA,iBACA,OAAA;EAAA,iBACA,UAAA;EAAA,QACT,KAAA;EAAA,QAGA,aAAA;EAAA,iBACS,UAAA;cAEL,IAAA,EAAM,oBAAA;;;;;;;;EAgBlB,gBAAA,CAAiB,MAAA;IAAU,YAAA;IAAsB,OAAA;IAAkB,OAAA;EAAA;;;;;;;;;;EAanE,WAAA,CAAY,KAAA,GAAQ,IAAA,aAAiB,OAAA;;;;;;;;;;;;EAe/B,UAAA,CAAA,GAAc,OAAA;;;;;;;;;;;EAmBd,QAAA,CAAS,MAAA;IACb,YAAA;IACA,OAAA;IAEA,OAAA;IACA,YAAA;EAAA,IACE,OAAA,CAAQ,wBAAA;;UAUJ,UAAA;;;;;;;;;;;;;;;EAoCF,YAAA,CACJ,KAAA,YACA,UAAA,IAAc,IAAA,UAAc,KAAA,oBAC3B,OAAA;IAAU,OAAA;IAAiB,MAAA;IAAgB,OAAA;EAAA;;;;;;;;;;;;;;;UAwChC,YAAA;;UAwMA,WAAA;;UAUA,aAAA;;;;;;;;;UAyBA,aAAA;;;;;;;;;;;;UAkDA,iBAAA;EAAA,QASN,iBAAA;EAAA,QAKM,UAAA;;;;;UAwHN,aAAA;AAAA"}
|