@odla-ai/kg 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-T6SYIVST.js +376 -0
- package/dist/chunk-T6SYIVST.js.map +1 -0
- package/dist/index.cjs +410 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +330 -5
- package/dist/index.d.ts +330 -5
- package/dist/index.js +249 -38
- package/dist/index.js.map +1 -1
- package/dist/lenses-C7Q7Gvnx.d.cts +123 -0
- package/dist/lenses-C7Q7Gvnx.d.ts +123 -0
- package/dist/temporal/index.cjs +1 -689
- package/dist/temporal/index.cjs.map +1 -1
- package/dist/temporal/index.d.cts +4 -565
- package/dist/temporal/index.d.ts +4 -565
- package/dist/temporal/index.js +20 -977
- package/dist/temporal/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-V3N2GRYU.js +0 -73
- package/dist/chunk-V3N2GRYU.js.map +0 -1
- package/dist/sources-nJyD0JUP.d.cts +0 -256
- package/dist/sources-nJyD0JUP.d.ts +0 -256
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import '@odla-ai/
|
|
1
|
+
import { b as GraphNode, G as GraphFragment } from '../lenses-C7Q7Gvnx.cjs';
|
|
2
|
+
export { W as WeightedPair, X as XY, d as blendPairs, f as composeTargets, g as directTargets, h as geoPairs, p as projectBridges, r as reifiedBridgeTargets, t as timePairs } from '../lenses-C7Q7Gvnx.cjs';
|
|
3
|
+
import '@odla-ai/db';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* FNV-1a 32-bit hash of a string. Used to derive a per-identity PRNG seed
|
|
@@ -76,209 +76,6 @@ declare function indexGraph(fragment: GraphFragment): GraphIndex;
|
|
|
76
76
|
*/
|
|
77
77
|
declare function resolvePath(g: GraphIndex, start: NodeRef, labels: readonly string[]): NodeRef[];
|
|
78
78
|
|
|
79
|
-
/**
|
|
80
|
-
* Where an event's geography lives: walk `path` (forward edge labels) from the
|
|
81
|
-
* event node, then read `attr` off the landing node — or, with no `attr`, use
|
|
82
|
-
* the landing node's key (e.g. a `region` entity slug). With no `path`, the
|
|
83
|
-
* event node itself is the landing node.
|
|
84
|
-
*/
|
|
85
|
-
interface GeoSpec {
|
|
86
|
-
path?: readonly string[];
|
|
87
|
-
attr?: string;
|
|
88
|
-
}
|
|
89
|
-
/** How to turn one entity type into temporal events. */
|
|
90
|
-
interface EventSpec {
|
|
91
|
-
/** Event entity type, e.g. `"funding_round"` or `"signal"`. */
|
|
92
|
-
type: string;
|
|
93
|
-
/** Attr holding the event date (parsed with `parseDateMs`; undated nodes are skipped). */
|
|
94
|
-
dateAttr: string;
|
|
95
|
-
/** Attr holding a magnitude, parsed with `parseAmount`; unparseable → weight 1. */
|
|
96
|
-
weightAttr?: string;
|
|
97
|
-
/** Override hook for weights the attr grammar can't express. */
|
|
98
|
-
weightOf?: (attrs: Record<string, Value>) => number | undefined;
|
|
99
|
-
/** Edge-label paths from the event node to its participant entities. */
|
|
100
|
-
attach?: readonly (readonly string[])[];
|
|
101
|
-
/** Geography of the event (choropleth/hotspot keying). */
|
|
102
|
-
geo?: GeoSpec;
|
|
103
|
-
/** Destination geography — only for flow-shaped events (money moving A→B). */
|
|
104
|
-
geoTo?: GeoSpec;
|
|
105
|
-
}
|
|
106
|
-
/** The extraction contract: one spec per event entity type. */
|
|
107
|
-
interface TemporalConfig {
|
|
108
|
-
events: EventSpec[];
|
|
109
|
-
}
|
|
110
|
-
/** One timestamped event extracted from the graph. */
|
|
111
|
-
interface TemporalEvent {
|
|
112
|
-
/** Epoch ms (UTC). */
|
|
113
|
-
t: number;
|
|
114
|
-
/** The spec's entity type. */
|
|
115
|
-
kind: string;
|
|
116
|
-
/** The event node itself. */
|
|
117
|
-
node: NodeRef;
|
|
118
|
-
/** Attached participant entities, deduped, sorted by id. */
|
|
119
|
-
refs: NodeRef[];
|
|
120
|
-
/** Magnitude (defaults to 1). */
|
|
121
|
-
weight: number;
|
|
122
|
-
/** Source geography key, when resolvable. */
|
|
123
|
-
geo?: string;
|
|
124
|
-
/** Destination geography key, when resolvable (flow events). */
|
|
125
|
-
geoTo?: string;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Parse a human money/quantity string to a number: `"$12.5M"` → 12500000,
|
|
129
|
-
* `"12,500,000"` → 12500000, `"500k"` → 500000, numbers pass through.
|
|
130
|
-
* Returns undefined for anything else (never NaN).
|
|
131
|
-
*/
|
|
132
|
-
declare function parseAmount(v: unknown): number | undefined;
|
|
133
|
-
/**
|
|
134
|
-
* Extract the event stream: for every spec, every node of that type with a
|
|
135
|
-
* parseable date becomes one event. Sorted by time, tie-broken by node id —
|
|
136
|
-
* the ordering is total and reproducible.
|
|
137
|
-
*/
|
|
138
|
-
declare function extractEvents(fragment: GraphFragment, config: TemporalConfig): TemporalEvent[];
|
|
139
|
-
|
|
140
|
-
/** One named series, index-aligned with its SeriesSet's buckets. */
|
|
141
|
-
interface Series {
|
|
142
|
-
key: string;
|
|
143
|
-
values: number[];
|
|
144
|
-
}
|
|
145
|
-
/** A grain, its buckets, and every series over them (sorted by key). */
|
|
146
|
-
interface SeriesSet {
|
|
147
|
-
grain: TimeGrain;
|
|
148
|
-
buckets: TimeBucket[];
|
|
149
|
-
series: Series[];
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* How to key events into series: `"kind"` (event type), `"geo"` (source
|
|
153
|
-
* geography; geo-less events are dropped), `"ref"` (fan one event into one
|
|
154
|
-
* increment per attached participant, keyed by node id), or a custom function
|
|
155
|
-
* returning zero or more keys per event.
|
|
156
|
-
*/
|
|
157
|
-
type SeriesKeyer = "kind" | "geo" | "ref" | ((e: TemporalEvent) => string | readonly string[] | undefined);
|
|
158
|
-
/** The series keys one event contributes to under a keyer (used by rollup and by hotspot contributor attachment). */
|
|
159
|
-
declare function seriesKeys(e: TemporalEvent, by: SeriesKeyer): readonly string[];
|
|
160
|
-
/**
|
|
161
|
-
* Roll events up into bucketed series. The bucket range spans `from`..`to`
|
|
162
|
-
* when given (zero-padded even where nothing happened — burst baselines need
|
|
163
|
-
* the quiet buckets), else the events' own time span. Events outside the
|
|
164
|
-
* range are ignored.
|
|
165
|
-
*/
|
|
166
|
-
declare function rollup(events: readonly TemporalEvent[], opts: {
|
|
167
|
-
grain: TimeGrain;
|
|
168
|
-
by?: SeriesKeyer;
|
|
169
|
-
measure?: "count" | "weight";
|
|
170
|
-
from?: number;
|
|
171
|
-
to?: number;
|
|
172
|
-
}): SeriesSet;
|
|
173
|
-
/** Per-bucket sum across every series in the set (the "all" line). */
|
|
174
|
-
declare function totals(set: SeriesSet): Series;
|
|
175
|
-
|
|
176
|
-
/** Tuning for {@link burstScores}/{@link detectBursts}. */
|
|
177
|
-
interface BurstOptions {
|
|
178
|
-
/** Trailing buckets forming the baseline (excluding the scored bucket). Default 6. */
|
|
179
|
-
window?: number;
|
|
180
|
-
/** z needed to OPEN a burst run. Default 2. */
|
|
181
|
-
zEnter?: number;
|
|
182
|
-
/** z needed to EXTEND an open run (hysteresis). Default 1. */
|
|
183
|
-
zExit?: number;
|
|
184
|
-
/** Minimum trailing buckets before scoring (cold start → z 0). Default 3. */
|
|
185
|
-
minBaseline?: number;
|
|
186
|
-
/**
|
|
187
|
-
* Floor on the baseline sigma. sqrt(mean) is always applied (Poisson-
|
|
188
|
-
* consistent for counts); this guards the all-zero baseline. Default 1.
|
|
189
|
-
*/
|
|
190
|
-
minSigma?: number;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Per-bucket burst z-scores for one series: (value − trailing mean) /
|
|
194
|
-
* max(trailing stdev, sqrt(mean), minSigma). Cold-start buckets score 0.
|
|
195
|
-
*/
|
|
196
|
-
declare function burstScores(values: readonly number[], opts?: BurstOptions): number[];
|
|
197
|
-
/** One detected burst: a maximal hysteresis run within one series. */
|
|
198
|
-
interface Burst {
|
|
199
|
-
seriesKey: string;
|
|
200
|
-
/** Bucket indexes, inclusive. */
|
|
201
|
-
start: number;
|
|
202
|
-
end: number;
|
|
203
|
-
/** Highest z in the run. */
|
|
204
|
-
peak: number;
|
|
205
|
-
/** Σ max(0, z) over the run — rewards both height and duration. */
|
|
206
|
-
score: number;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* All bursts across a SeriesSet, ranked score desc (ties: earlier start,
|
|
210
|
-
* then series key). A run opens at z ≥ zEnter and extends while z ≥ zExit.
|
|
211
|
-
*/
|
|
212
|
-
declare function detectBursts(set: SeriesSet, opts?: BurstOptions): Burst[];
|
|
213
|
-
/** A burst plus its bucket keys and top contributing events — a ranked lead. */
|
|
214
|
-
interface Hotspot extends Burst {
|
|
215
|
-
bucketKeys: string[];
|
|
216
|
-
contributors: TemporalEvent[];
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Detect, rank, and enrich bursts into explorable leads. `by` must be the
|
|
220
|
-
* same keyer the SeriesSet was rolled up with — it re-derives each event's
|
|
221
|
-
* series keys to attach contributors (top per-lead by weight, then time).
|
|
222
|
-
*/
|
|
223
|
-
declare function rankHotspots(set: SeriesSet, events: readonly TemporalEvent[], opts?: BurstOptions & {
|
|
224
|
-
by?: SeriesKeyer;
|
|
225
|
-
top?: number;
|
|
226
|
-
contributorsPer?: number;
|
|
227
|
-
}): Hotspot[];
|
|
228
|
-
|
|
229
|
-
/** One dated undirected edge (canonical order: a < b). */
|
|
230
|
-
interface TimelineEdge {
|
|
231
|
-
a: NodeId;
|
|
232
|
-
b: NodeId;
|
|
233
|
-
t: number;
|
|
234
|
-
kind: string;
|
|
235
|
-
weight: number;
|
|
236
|
-
}
|
|
237
|
-
/** The replayable structure built once from the event stream. */
|
|
238
|
-
interface Timeline {
|
|
239
|
-
events: TemporalEvent[];
|
|
240
|
-
/** Every node ever seen, sorted by id. */
|
|
241
|
-
nodes: NodeId[];
|
|
242
|
-
/** Dated edges, time-ordered. */
|
|
243
|
-
edges: TimelineEdge[];
|
|
244
|
-
/** Node id → first time it appeared. */
|
|
245
|
-
firstSeen: Map<NodeId, number>;
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Build the timeline. `"entities"` (default) projects each event onto its
|
|
249
|
-
* participants — every ref pair co-occurring in one event becomes an edge
|
|
250
|
-
* (companies↔investors↔people), and event nodes vanish. `"full"` keeps the
|
|
251
|
-
* event node and links it to each ref (bipartite).
|
|
252
|
-
*/
|
|
253
|
-
declare function buildTimeline(events: readonly TemporalEvent[], opts?: {
|
|
254
|
-
mode?: "entities" | "full";
|
|
255
|
-
}): Timeline;
|
|
256
|
-
/** The graph as it stood at time `t`. */
|
|
257
|
-
interface Snapshot {
|
|
258
|
-
t: number;
|
|
259
|
-
/** Nodes first seen at or before t, sorted. */
|
|
260
|
-
nodes: NodeId[];
|
|
261
|
-
/** Aggregated undirected edges (weight = co-occurrence count). */
|
|
262
|
-
edges: Array<{
|
|
263
|
-
a: NodeId;
|
|
264
|
-
b: NodeId;
|
|
265
|
-
weight: number;
|
|
266
|
-
}>;
|
|
267
|
-
/** Node id → its latest event time ≤ t (drives recency glow). */
|
|
268
|
-
activity: Map<NodeId, number>;
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Materialize the graph at `t`: cumulative by default, or only edges within
|
|
272
|
-
* the trailing `window` ms when given (rolling co-activity).
|
|
273
|
-
*/
|
|
274
|
-
declare function snapshotAt(timeline: Timeline, t: number, opts?: {
|
|
275
|
-
window?: number;
|
|
276
|
-
}): Snapshot;
|
|
277
|
-
/** One snapshot per bucket, each taken at the bucket's inclusive end. */
|
|
278
|
-
declare function snapshotSeries(timeline: Timeline, buckets: readonly TimeBucket[], opts?: {
|
|
279
|
-
window?: number;
|
|
280
|
-
}): Snapshot[];
|
|
281
|
-
|
|
282
79
|
/**
|
|
283
80
|
* Asynchronous label propagation with deterministic (seeded) tie-breaking:
|
|
284
81
|
* - labels start as each node's own id;
|
|
@@ -302,364 +99,6 @@ declare function labelPropagation(nodes: readonly NodeId[], edges: ReadonlyArray
|
|
|
302
99
|
maxRounds?: number;
|
|
303
100
|
}): Map<NodeId, string>;
|
|
304
101
|
|
|
305
|
-
/** One cluster in one frame (members sorted). */
|
|
306
|
-
interface Cluster {
|
|
307
|
-
id: string;
|
|
308
|
-
members: NodeId[];
|
|
309
|
-
}
|
|
310
|
-
/** All clusters at one instant, id-sorted. */
|
|
311
|
-
interface ClusterFrame {
|
|
312
|
-
t: number;
|
|
313
|
-
clusters: Cluster[];
|
|
314
|
-
}
|
|
315
|
-
/** A structural change between consecutive frames. */
|
|
316
|
-
type ClusterChange = {
|
|
317
|
-
kind: "birth";
|
|
318
|
-
t: number;
|
|
319
|
-
id: string;
|
|
320
|
-
} | {
|
|
321
|
-
kind: "death";
|
|
322
|
-
t: number;
|
|
323
|
-
id: string;
|
|
324
|
-
} | {
|
|
325
|
-
kind: "merge";
|
|
326
|
-
t: number;
|
|
327
|
-
into: string;
|
|
328
|
-
from: string[];
|
|
329
|
-
} | {
|
|
330
|
-
kind: "split";
|
|
331
|
-
t: number;
|
|
332
|
-
from: string;
|
|
333
|
-
into: string[];
|
|
334
|
-
};
|
|
335
|
-
/**
|
|
336
|
-
* Thread stable cluster ids through per-frame label maps. A current cluster
|
|
337
|
-
* inherits the id of its best-Jaccard predecessor at ≥ minJaccard (ties:
|
|
338
|
-
* more shared members, then smaller id); when several current clusters claim
|
|
339
|
-
* one predecessor the best keeps the id and the rest record a split; a
|
|
340
|
-
* current cluster absorbing ≥2 predecessors records a merge. Unmatched
|
|
341
|
-
* current clusters are births (id = "c:" + smallest member); vanished ids
|
|
342
|
-
* are deaths.
|
|
343
|
-
*/
|
|
344
|
-
declare function trackClusters(frames: ReadonlyArray<{
|
|
345
|
-
t: number;
|
|
346
|
-
labels: Map<NodeId, string>;
|
|
347
|
-
}>, opts?: {
|
|
348
|
-
minJaccard?: number;
|
|
349
|
-
}): {
|
|
350
|
-
frames: ClusterFrame[];
|
|
351
|
-
changes: ClusterChange[];
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
/** A unit-square position (scale to pixels at draw time). */
|
|
355
|
-
interface XY {
|
|
356
|
-
x: number;
|
|
357
|
-
y: number;
|
|
358
|
-
}
|
|
359
|
-
/** Tuning for {@link forceLayout}. */
|
|
360
|
-
interface LayoutOptions {
|
|
361
|
-
/** Force iterations. Default 300 (cold); use fewer for warm refinement. */
|
|
362
|
-
iterations?: number;
|
|
363
|
-
/** Seed mixed into every node's hash-derived initial position. Default 1. */
|
|
364
|
-
seed?: number;
|
|
365
|
-
/**
|
|
366
|
-
* Repulsion multiplier. Default 0.1 — measured on a real ~800-node OSINT
|
|
367
|
-
* graph as the point where nothing pins to the clamped boundary.
|
|
368
|
-
*/
|
|
369
|
-
repulsion?: number;
|
|
370
|
-
/** Pull toward the center, proportional to distance. Default 0.5. */
|
|
371
|
-
gravity?: number;
|
|
372
|
-
/** Warm-start positions (nodes present here start where they were). */
|
|
373
|
-
positions?: ReadonlyMap<NodeId, XY>;
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Lay out one graph. Init priority per node: warm `positions` entry →
|
|
377
|
-
* hash-disc from (id, seed). Forces per iteration (accumulated over
|
|
378
|
-
* sorted-id order, applied synchronously): pairwise repulsion k²/d, edge
|
|
379
|
-
* attraction d²/k scaled by min(weight, 4), center gravity. Linear cooling
|
|
380
|
-
* caps displacement; results clamp to [0,1]².
|
|
381
|
-
*/
|
|
382
|
-
declare function forceLayout(nodes: readonly NodeId[], edges: ReadonlyArray<{
|
|
383
|
-
a: NodeId;
|
|
384
|
-
b: NodeId;
|
|
385
|
-
weight?: number;
|
|
386
|
-
}>, opts?: LayoutOptions): Map<NodeId, XY>;
|
|
387
|
-
/**
|
|
388
|
-
* Lay out a snapshot sequence: frame 0 runs cold (`iterations`), each later
|
|
389
|
-
* frame warm-starts from the previous frame's positions and refines for
|
|
390
|
-
* `warmIterations` — existing nodes drift instead of re-scrambling, so
|
|
391
|
-
* inter-frame motion means something.
|
|
392
|
-
*/
|
|
393
|
-
declare function layoutSequence(snapshots: readonly Snapshot[], opts?: LayoutOptions & {
|
|
394
|
-
warmIterations?: number;
|
|
395
|
-
}): Map<NodeId, XY>[];
|
|
396
|
-
|
|
397
|
-
/** Tuning for {@link buildTemporalReport}. */
|
|
398
|
-
interface ReportOptions {
|
|
399
|
-
/** Analysis anchor (epoch ms). Default: the latest event time. Inject for determinism. */
|
|
400
|
-
now?: number;
|
|
401
|
-
/** Weekly cluster/lead window. Default 155 days (~22 frames). */
|
|
402
|
-
windowDays?: number;
|
|
403
|
-
/** Monthly density-series span. Default 12 months. */
|
|
404
|
-
monthlyMonths?: number;
|
|
405
|
-
/** Ranked leads kept. Default 8. */
|
|
406
|
-
topLeads?: number;
|
|
407
|
-
/** Contributing events per lead. Default 3. */
|
|
408
|
-
contributorsPer?: number;
|
|
409
|
-
/** Trailing weeks of cluster changes kept. Default 4. */
|
|
410
|
-
changeWeeks?: number;
|
|
411
|
-
/** Burst detector tuning. Default `{ window: 6 }`. */
|
|
412
|
-
burst?: BurstOptions;
|
|
413
|
-
}
|
|
414
|
-
/** One ranked hotspot lead: a bursting entity plus its evidence. */
|
|
415
|
-
interface ReportLead {
|
|
416
|
-
key: string;
|
|
417
|
-
type: string;
|
|
418
|
-
name: string;
|
|
419
|
-
city?: string;
|
|
420
|
-
sector?: string;
|
|
421
|
-
score: number;
|
|
422
|
-
peak: number;
|
|
423
|
-
window: string[];
|
|
424
|
-
contributors: Array<{
|
|
425
|
-
kind: string;
|
|
426
|
-
key: string;
|
|
427
|
-
title: string;
|
|
428
|
-
date: string;
|
|
429
|
-
}>;
|
|
430
|
-
}
|
|
431
|
-
/** One cluster-evolution change, name-resolved for display. */
|
|
432
|
-
interface ReportClusterChange {
|
|
433
|
-
week: string;
|
|
434
|
-
kind: "birth" | "death" | "merge" | "split";
|
|
435
|
-
ids: string[];
|
|
436
|
-
names: string[];
|
|
437
|
-
}
|
|
438
|
-
/** The cached/served analysis product — everything JSON-native and bounded (≲20KB). */
|
|
439
|
-
interface TemporalReport {
|
|
440
|
-
generatedAt: string;
|
|
441
|
-
window: {
|
|
442
|
-
from: string;
|
|
443
|
-
to: string;
|
|
444
|
-
weeks: string[];
|
|
445
|
-
};
|
|
446
|
-
totals: {
|
|
447
|
-
events: number;
|
|
448
|
-
nodes: number;
|
|
449
|
-
edges: number;
|
|
450
|
-
};
|
|
451
|
-
series: Array<{
|
|
452
|
-
kind: string;
|
|
453
|
-
months: string[];
|
|
454
|
-
values: number[];
|
|
455
|
-
}>;
|
|
456
|
-
leads: ReportLead[];
|
|
457
|
-
clusters: {
|
|
458
|
-
frames: Array<{
|
|
459
|
-
week: string;
|
|
460
|
-
count: number;
|
|
461
|
-
top: Array<{
|
|
462
|
-
id: string;
|
|
463
|
-
size: number;
|
|
464
|
-
label: string;
|
|
465
|
-
}>;
|
|
466
|
-
}>;
|
|
467
|
-
changes: ReportClusterChange[];
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
/** Build the full temporal report for a graph fragment. Empty input → zeroed report. */
|
|
471
|
-
declare function buildTemporalReport(fragment: GraphFragment, config: TemporalConfig, opts?: ReportOptions): TemporalReport;
|
|
472
|
-
|
|
473
|
-
/** True when the report has anything worth narrating (any lead or recent cluster change). */
|
|
474
|
-
declare function shouldNarrate(report: TemporalReport): boolean;
|
|
475
|
-
/**
|
|
476
|
-
* The deterministic materials block handed to the narrative LLM call:
|
|
477
|
-
* window/totals header, top leads with evidence, cluster changes, and
|
|
478
|
-
* per-kind monthly density lines. No prose, no interpretation.
|
|
479
|
-
*/
|
|
480
|
-
declare function buildNarrationMaterials(report: TemporalReport, opts?: {
|
|
481
|
-
topLeads?: number;
|
|
482
|
-
}): string;
|
|
483
|
-
/** First-line `# title` heuristic shared with the digest workflow. */
|
|
484
|
-
declare function splitTitleBody(text: string, fallbackTitle: string): {
|
|
485
|
-
title: string;
|
|
486
|
-
body: string;
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Burst score per natural key for one entity type, from a report's leads:
|
|
491
|
-
* `{ leads: [{key: "company:acme", score: 7.3}] }` → `{ acme: 7.3 }`.
|
|
492
|
-
*/
|
|
493
|
-
declare function leadScores(report: Pick<TemporalReport, "leads">, type?: string): Record<string, number>;
|
|
494
|
-
/** One selected enrichment target. */
|
|
495
|
-
interface EnrichmentCandidate {
|
|
496
|
-
slug: string;
|
|
497
|
-
name: string;
|
|
498
|
-
score: number;
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Rank enrichment candidates: burst score descending, ties keep the input
|
|
502
|
-
* (creation) order. Cooling rows are skipped at selection. Complete rows are
|
|
503
|
-
* skipped UNLESS they carry a burst score — a bursting complete company
|
|
504
|
-
* deserves a re-check. With no scores this reproduces the legacy behavior
|
|
505
|
-
* exactly (input order, incomplete rows only).
|
|
506
|
-
*/
|
|
507
|
-
declare function rankEnrichmentCandidates(rows: ReadonlyArray<Record<string, unknown>>, opts: {
|
|
508
|
-
limit: number;
|
|
509
|
-
scores?: Record<string, number>;
|
|
510
|
-
cooling?: ReadonlySet<string>;
|
|
511
|
-
isComplete?: (row: Record<string, unknown>) => boolean;
|
|
512
|
-
}): EnrichmentCandidate[];
|
|
513
|
-
/**
|
|
514
|
-
* Replace the synthesized burst-sweep source with a fresh one derived from
|
|
515
|
-
* the report's top company leads (or remove it when there are none).
|
|
516
|
-
* Hand-authored entries — anything without `origin: "burst"` — are returned
|
|
517
|
-
* untouched, in order. Queries follow
|
|
518
|
-
* `"<name>" <city|sector|startup> funding OR expansion OR hiring news`.
|
|
519
|
-
*/
|
|
520
|
-
declare function synthesizeBurstSources(existing: readonly SourceEntry[], report: Pick<TemporalReport, "leads">, opts?: {
|
|
521
|
-
max?: number;
|
|
522
|
-
cadenceHours?: number;
|
|
523
|
-
}): SourceEntry[];
|
|
524
|
-
|
|
525
|
-
/** One aggregated movement between two geography keys within a bucket. */
|
|
526
|
-
interface Flow {
|
|
527
|
-
from: string;
|
|
528
|
-
to: string;
|
|
529
|
-
/** Summed event weights (e.g. dollars). */
|
|
530
|
-
weight: number;
|
|
531
|
-
/** Number of contributing events. */
|
|
532
|
-
count: number;
|
|
533
|
-
}
|
|
534
|
-
/** All flows for one time bucket, sorted weight-desc then from/to. */
|
|
535
|
-
interface FlowFrame {
|
|
536
|
-
bucket: TimeBucket;
|
|
537
|
-
flows: Flow[];
|
|
538
|
-
}
|
|
539
|
-
/**
|
|
540
|
-
* Aggregate flow events into per-bucket frames over `from`..`to` (default:
|
|
541
|
-
* the events' span). With `cumulative`, each frame includes everything up to
|
|
542
|
-
* and including its bucket — replay-style accumulation.
|
|
543
|
-
*/
|
|
544
|
-
declare function flowFrames(events: readonly TemporalEvent[], opts: {
|
|
545
|
-
grain: TimeGrain;
|
|
546
|
-
from?: number;
|
|
547
|
-
to?: number;
|
|
548
|
-
cumulative?: boolean;
|
|
549
|
-
}): FlowFrame[];
|
|
550
|
-
/** The frame's top-n flows by weight (already the frame's sort order). */
|
|
551
|
-
declare function topFlows(frame: FlowFrame, n: number): Flow[];
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* One threshold rule over a region's static metrics. A rule matches when the
|
|
555
|
-
* region has the metric and its value passes the comparison; regions or
|
|
556
|
-
* metrics missing from the metric map never match (and never throw).
|
|
557
|
-
*/
|
|
558
|
-
interface SpatialRule {
|
|
559
|
-
/** Stable identifier, reported on findings (e.g. `"capital-desert"`). */
|
|
560
|
-
id: string;
|
|
561
|
-
/** Metric name looked up in the region's metric record. */
|
|
562
|
-
metric: string;
|
|
563
|
-
/** Comparison direction against {@link threshold}. */
|
|
564
|
-
op: ">=" | "<=";
|
|
565
|
-
threshold: number;
|
|
566
|
-
/** Additive score boost when matched (finding score × (1 + Σ weights)). Default 1. */
|
|
567
|
-
weight?: number;
|
|
568
|
-
}
|
|
569
|
-
/** A bursting region, the rules it matched, and its boosted rank score. */
|
|
570
|
-
interface SpatialFinding {
|
|
571
|
-
/** The series key — the region identifier the events were rolled up by. */
|
|
572
|
-
region: string;
|
|
573
|
-
/** The region's strongest burst (highest score) in the set. */
|
|
574
|
-
burst: Burst;
|
|
575
|
-
/** Ids of the rules that matched, in the rules' given order. */
|
|
576
|
-
matched: string[];
|
|
577
|
-
/** `burst.score × (1 + Σ matched weights)` — rule context amplifies heat. */
|
|
578
|
-
score: number;
|
|
579
|
-
/** The region's values for every rule metric it has (evidence for narration). */
|
|
580
|
-
metrics: Record<string, number>;
|
|
581
|
-
}
|
|
582
|
-
/** Ids of the rules a region's metric record matches, in rule order. */
|
|
583
|
-
declare function matchRules(values: Record<string, number> | undefined, rules: readonly SpatialRule[]): string[];
|
|
584
|
-
/**
|
|
585
|
-
* Rank spatial anomalies: detect bursts in a geo-keyed SeriesSet (one series
|
|
586
|
-
* per region — roll up with `by: "geo"`), keep each region's strongest burst,
|
|
587
|
-
* then amplify by matched metric rules. Deterministic: score desc, then
|
|
588
|
-
* region asc. `requireMatch` drops regions matching no rule (default keeps
|
|
589
|
-
* them — a burst is a finding even without metric context).
|
|
590
|
-
*/
|
|
591
|
-
declare function spatialFindings(set: SeriesSet, metrics: Record<string, Record<string, number> | undefined>, rules: readonly SpatialRule[], opts?: BurstOptions & {
|
|
592
|
-
top?: number;
|
|
593
|
-
requireMatch?: boolean;
|
|
594
|
-
}): SpatialFinding[];
|
|
595
|
-
|
|
596
|
-
/** One undirected weighted pair, with (capped) bridging node ids as evidence. */
|
|
597
|
-
interface WeightedPair {
|
|
598
|
-
a: string;
|
|
599
|
-
b: string;
|
|
600
|
-
w: number;
|
|
601
|
-
via: string[];
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Bridge → target sets through a REIFIED relationship node (affiliation,
|
|
605
|
-
* funding_round, record): every reified node with a `bridgeLabel` edge to the
|
|
606
|
-
* bridge and a `targetLabel` edge to a target contributes that target to the
|
|
607
|
-
* bridge's set. Ids are `type:key`.
|
|
608
|
-
*/
|
|
609
|
-
declare function reifiedBridgeTargets(fragment: GraphFragment, opts: {
|
|
610
|
-
reified: string;
|
|
611
|
-
bridgeLabel: string;
|
|
612
|
-
targetLabel: string;
|
|
613
|
-
}): Map<string, Set<string>>;
|
|
614
|
-
/** Direct-edge targets: `from` node id → set of `to` node ids for one label. */
|
|
615
|
-
declare function directTargets(fragment: GraphFragment, label: string): Map<string, Set<string>>;
|
|
616
|
-
/** Compose A→B with B→C into A→C (e.g. person→companies ∘ company→counties). */
|
|
617
|
-
declare function composeTargets(ab: Map<string, Set<string>>, bc: Map<string, Set<string>>): Map<string, Set<string>>;
|
|
618
|
-
/**
|
|
619
|
-
* The bipartite projection: targets sharing a bridge become pairs, weight =
|
|
620
|
-
* number of distinct shared bridges. `maxPerBridge` skips promiscuous hubs
|
|
621
|
-
* (a bridge touching 40 targets says little about any pair). Deterministic
|
|
622
|
-
* pair order (a < b, then sorted).
|
|
623
|
-
*/
|
|
624
|
-
declare function projectBridges(bridges: Map<string, Set<string>>, opts?: {
|
|
625
|
-
maxPerBridge?: number;
|
|
626
|
-
viaCap?: number;
|
|
627
|
-
}): WeightedPair[];
|
|
628
|
-
/**
|
|
629
|
-
* Temporal cohort pairs: each node links to its k nearest neighbors in
|
|
630
|
-
* arrival time, weight decaying with the gap (0.5 per halfLife). Nodes
|
|
631
|
-
* without a date contribute nothing.
|
|
632
|
-
*/
|
|
633
|
-
declare function timePairs(arrivals: Map<string, number>, opts?: {
|
|
634
|
-
k?: number;
|
|
635
|
-
halfLifeDays?: number;
|
|
636
|
-
}): WeightedPair[];
|
|
637
|
-
/**
|
|
638
|
-
* Spatial proximity pairs: k nearest neighbors in normalized map space,
|
|
639
|
-
* weight decaying with distance (0.5 per halfDist). Nodes without a
|
|
640
|
-
* position contribute nothing. O(n²) — fine for the ≤1k-node universes
|
|
641
|
-
* lenses operate on.
|
|
642
|
-
*/
|
|
643
|
-
declare function geoPairs(positions: Map<string, XY>, opts?: {
|
|
644
|
-
k?: number;
|
|
645
|
-
halfDist?: number;
|
|
646
|
-
}): WeightedPair[];
|
|
647
|
-
/**
|
|
648
|
-
* Blend lens edge sets: each set is normalized to a max weight of 1 (a lens
|
|
649
|
-
* with big raw counts must not drown the others), scaled by its slider
|
|
650
|
-
* weight, and summed per pair. Zero-weight lenses drop out entirely.
|
|
651
|
-
*/
|
|
652
|
-
declare function blendPairs(sets: Array<{
|
|
653
|
-
pairs: WeightedPair[];
|
|
654
|
-
weight: number;
|
|
655
|
-
}>): WeightedPair[];
|
|
656
|
-
/**
|
|
657
|
-
* Fabricate the Snapshot series a lens graph replays: at each bucket end,
|
|
658
|
-
* nodes that have arrived and the blended edges among them. Slots straight
|
|
659
|
-
* into labelPropagation/trackClusters/layoutSequence.
|
|
660
|
-
*/
|
|
661
|
-
declare function lensSnapshots(arrivals: Map<string, number>, pairs: WeightedPair[], buckets: readonly TimeBucket[]): Snapshot[];
|
|
662
|
-
|
|
663
102
|
/** One node's brokerage: normalized score + the communities it connects. */
|
|
664
103
|
interface Bridging {
|
|
665
104
|
/** 0..1, 1 = the frame's strongest connector. */
|
|
@@ -687,4 +126,4 @@ declare function topBridges(bridging: Map<NodeId, Bridging>, n?: number): Array<
|
|
|
687
126
|
groups: string[];
|
|
688
127
|
}>;
|
|
689
128
|
|
|
690
|
-
export { type Bridging, type
|
|
129
|
+
export { type Bridging, type GraphIndex, type NodeId, type NodeRef, type TimeBucket, type TimeGrain, bridgingScores, bucketFor, bucketKey, bucketRange, byNodeId, hash32, indexGraph, labelPropagation, mulberry32, nodeId, parseDateMs, resolvePath, shuffle, topBridges };
|