@neat.is/core 0.4.26-dev.20260703 → 0.4.26

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/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MultiDirectedGraph } from 'graphology';
2
- import { GraphNode, GraphEdge, StaleEvent, ErrorEvent, BlastRadiusResult, RootCauseResult, RegistryEntry, RegistryStatus, RegistryFile } from '@neat.is/types';
2
+ import { GraphNode, GraphEdge, StaleEvent, ErrorEvent, BlastRadiusResult, RootCauseResult, EdgeTypeValue, RegistryEntry, RegistryStatus, RegistryFile } from '@neat.is/types';
3
3
  export { StaleEvent } from '@neat.is/types';
4
4
  import { FastifyInstance } from 'fastify';
5
5
 
@@ -156,6 +156,10 @@ interface ParsedSpan {
156
156
  messagingDestination?: string;
157
157
  graphqlOperationName?: string;
158
158
  graphqlOperationType?: string;
159
+ rpcSystem?: string;
160
+ rpcService?: string;
161
+ rpcMethod?: string;
162
+ websocketChannel?: string;
159
163
  statusCode?: number;
160
164
  errorMessage?: string;
161
165
  exception?: {
@@ -339,6 +343,96 @@ interface GraphDiff {
339
343
  declare function loadSnapshotForDiff(target: string): Promise<PersistedSnapshot>;
340
344
  declare function computeGraphDiff(liveGraph: NeatGraph, baseSnapshot: PersistedSnapshot, currentExportedAt?: string): GraphDiff;
341
345
 
346
+ /**
347
+ * A connector implements exactly one method. Everything downstream of
348
+ * `poll()` — resolving a static call site, minting the OBSERVED edge — is
349
+ * shared, generic code in connectors/index.ts.
350
+ */
351
+ interface ObservedConnector {
352
+ readonly provider: string;
353
+ poll(ctx: ConnectorContext): Promise<ObservedSignal[]>;
354
+ }
355
+ /**
356
+ * Everything a connector's `poll()` needs, resolved once at connector setup
357
+ * — never re-derived at poll time.
358
+ *
359
+ * `credentials` is opaque here on purpose: its shape is entirely provider-
360
+ * and profile-defined (local vs hosted — docs/contracts/connectors.md §3).
361
+ * It flows through to `poll()` only. Never log it, never write it into a
362
+ * node or edge, never let it reach the graph snapshot (contract §6, and the
363
+ * `.env`-contents rule docs/contracts.md Rule 4 already states for local
364
+ * config).
365
+ */
366
+ interface ConnectorContext {
367
+ projectDir: string;
368
+ credentials: Record<string, unknown>;
369
+ since?: string;
370
+ }
371
+ /**
372
+ * `file:line` the provider's own signal carries, when it does (rare — see
373
+ * docs/connectors/README.md §Provider interface, which notes this is
374
+ * "usually resolved by the mapping layer below, not here"). Reconciled onto
375
+ * the EXTRACTED service-relative path by the shared fuse step the same way
376
+ * an OTel span's call site is (file-awareness.md §4).
377
+ */
378
+ interface ConnectorCallSite {
379
+ file: string;
380
+ line: number;
381
+ }
382
+ /**
383
+ * One provider-agnostic observation. `targetKind`/`targetName` are the
384
+ * provider's own vocabulary (`'supabase-table'`/`'orders'`,
385
+ * `'route'`/`'GET /users/:id'`, ...) — resolving that pair to a NEAT node id
386
+ * is the one genuinely provider-specific step (README.md's pipeline
387
+ * diagram), supplied to `runConnectorPoll` (connectors/index.ts) as a
388
+ * `resolveTarget` callback. Everything downstream of that resolution — file
389
+ * grain fusion, OBSERVED mint — is shared.
390
+ */
391
+ interface ObservedSignal {
392
+ targetKind: string;
393
+ targetName: string;
394
+ callCount: number;
395
+ errorCount: number;
396
+ lastObservedIso: string;
397
+ callSite?: ConnectorCallSite;
398
+ }
399
+
400
+ /**
401
+ * What a provider's target-resolution step hands back for one signal. The
402
+ * generic pipeline needs both endpoints of the edge it's about to mint:
403
+ *
404
+ * - `serviceName` is the NEAT manifest service whose code produced the
405
+ * signal — the edge's source. The shared pipeline turns it into a plain
406
+ * ServiceNode id, or a FileNode id once the fuse step below resolves the
407
+ * signal's callSite against it.
408
+ * - `targetNodeId` is the id the provider's own mapping already resolved —
409
+ * an `infraId(...)` sub-resource, a RouteNode, a ServiceNode, whatever
410
+ * (see each provider's docs/connectors/<provider>.md §Fusion).
411
+ *
412
+ * Returning `null` skips the signal honestly: an unresolvable target never
413
+ * fabricates a node or edge (the same discipline file-awareness.md §6
414
+ * states for OTel ingest).
415
+ */
416
+ interface ResolvedConnectorTarget {
417
+ targetNodeId: string;
418
+ serviceName: string;
419
+ edgeType: EdgeTypeValue;
420
+ }
421
+ type ResolveConnectorTarget = (signal: ObservedSignal, ctx: ConnectorContext) => ResolvedConnectorTarget | null;
422
+ /**
423
+ * One project's registered connector, ready for `daemon.ts` to poll on an
424
+ * interval. Deliberately thin — no config-loading or credential-broker logic
425
+ * lives here (that's provider- and profile-specific, later work per
426
+ * docs/contracts/connectors.md §3); this is just the seam a daemon slot
427
+ * wires a connector through.
428
+ */
429
+ interface ConnectorRegistration {
430
+ connector: ObservedConnector;
431
+ credentials: Record<string, unknown>;
432
+ resolveTarget: ResolveConnectorTarget;
433
+ intervalMs?: number;
434
+ }
435
+
342
436
  /**
343
437
  * Multi-project daemon (ADR-049).
344
438
  *
@@ -390,6 +484,7 @@ interface DaemonOptions {
390
484
  otlpPort?: number;
391
485
  host?: string;
392
486
  bindListeners?: boolean;
487
+ connectors?: ConnectorRegistration[];
393
488
  }
394
489
  interface ProjectSlot {
395
490
  entry: RegistryEntry;
@@ -398,6 +493,7 @@ interface ProjectSlot {
398
493
  paths: ProjectPaths;
399
494
  stopPersist: () => void;
400
495
  stopStaleness: () => void;
496
+ stopConnectors: () => void;
401
497
  detachEvents: () => void;
402
498
  status: 'active' | 'broken';
403
499
  errorReason?: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MultiDirectedGraph } from 'graphology';
2
- import { GraphNode, GraphEdge, StaleEvent, ErrorEvent, BlastRadiusResult, RootCauseResult, RegistryEntry, RegistryStatus, RegistryFile } from '@neat.is/types';
2
+ import { GraphNode, GraphEdge, StaleEvent, ErrorEvent, BlastRadiusResult, RootCauseResult, EdgeTypeValue, RegistryEntry, RegistryStatus, RegistryFile } from '@neat.is/types';
3
3
  export { StaleEvent } from '@neat.is/types';
4
4
  import { FastifyInstance } from 'fastify';
5
5
 
@@ -156,6 +156,10 @@ interface ParsedSpan {
156
156
  messagingDestination?: string;
157
157
  graphqlOperationName?: string;
158
158
  graphqlOperationType?: string;
159
+ rpcSystem?: string;
160
+ rpcService?: string;
161
+ rpcMethod?: string;
162
+ websocketChannel?: string;
159
163
  statusCode?: number;
160
164
  errorMessage?: string;
161
165
  exception?: {
@@ -339,6 +343,96 @@ interface GraphDiff {
339
343
  declare function loadSnapshotForDiff(target: string): Promise<PersistedSnapshot>;
340
344
  declare function computeGraphDiff(liveGraph: NeatGraph, baseSnapshot: PersistedSnapshot, currentExportedAt?: string): GraphDiff;
341
345
 
346
+ /**
347
+ * A connector implements exactly one method. Everything downstream of
348
+ * `poll()` — resolving a static call site, minting the OBSERVED edge — is
349
+ * shared, generic code in connectors/index.ts.
350
+ */
351
+ interface ObservedConnector {
352
+ readonly provider: string;
353
+ poll(ctx: ConnectorContext): Promise<ObservedSignal[]>;
354
+ }
355
+ /**
356
+ * Everything a connector's `poll()` needs, resolved once at connector setup
357
+ * — never re-derived at poll time.
358
+ *
359
+ * `credentials` is opaque here on purpose: its shape is entirely provider-
360
+ * and profile-defined (local vs hosted — docs/contracts/connectors.md §3).
361
+ * It flows through to `poll()` only. Never log it, never write it into a
362
+ * node or edge, never let it reach the graph snapshot (contract §6, and the
363
+ * `.env`-contents rule docs/contracts.md Rule 4 already states for local
364
+ * config).
365
+ */
366
+ interface ConnectorContext {
367
+ projectDir: string;
368
+ credentials: Record<string, unknown>;
369
+ since?: string;
370
+ }
371
+ /**
372
+ * `file:line` the provider's own signal carries, when it does (rare — see
373
+ * docs/connectors/README.md §Provider interface, which notes this is
374
+ * "usually resolved by the mapping layer below, not here"). Reconciled onto
375
+ * the EXTRACTED service-relative path by the shared fuse step the same way
376
+ * an OTel span's call site is (file-awareness.md §4).
377
+ */
378
+ interface ConnectorCallSite {
379
+ file: string;
380
+ line: number;
381
+ }
382
+ /**
383
+ * One provider-agnostic observation. `targetKind`/`targetName` are the
384
+ * provider's own vocabulary (`'supabase-table'`/`'orders'`,
385
+ * `'route'`/`'GET /users/:id'`, ...) — resolving that pair to a NEAT node id
386
+ * is the one genuinely provider-specific step (README.md's pipeline
387
+ * diagram), supplied to `runConnectorPoll` (connectors/index.ts) as a
388
+ * `resolveTarget` callback. Everything downstream of that resolution — file
389
+ * grain fusion, OBSERVED mint — is shared.
390
+ */
391
+ interface ObservedSignal {
392
+ targetKind: string;
393
+ targetName: string;
394
+ callCount: number;
395
+ errorCount: number;
396
+ lastObservedIso: string;
397
+ callSite?: ConnectorCallSite;
398
+ }
399
+
400
+ /**
401
+ * What a provider's target-resolution step hands back for one signal. The
402
+ * generic pipeline needs both endpoints of the edge it's about to mint:
403
+ *
404
+ * - `serviceName` is the NEAT manifest service whose code produced the
405
+ * signal — the edge's source. The shared pipeline turns it into a plain
406
+ * ServiceNode id, or a FileNode id once the fuse step below resolves the
407
+ * signal's callSite against it.
408
+ * - `targetNodeId` is the id the provider's own mapping already resolved —
409
+ * an `infraId(...)` sub-resource, a RouteNode, a ServiceNode, whatever
410
+ * (see each provider's docs/connectors/<provider>.md §Fusion).
411
+ *
412
+ * Returning `null` skips the signal honestly: an unresolvable target never
413
+ * fabricates a node or edge (the same discipline file-awareness.md §6
414
+ * states for OTel ingest).
415
+ */
416
+ interface ResolvedConnectorTarget {
417
+ targetNodeId: string;
418
+ serviceName: string;
419
+ edgeType: EdgeTypeValue;
420
+ }
421
+ type ResolveConnectorTarget = (signal: ObservedSignal, ctx: ConnectorContext) => ResolvedConnectorTarget | null;
422
+ /**
423
+ * One project's registered connector, ready for `daemon.ts` to poll on an
424
+ * interval. Deliberately thin — no config-loading or credential-broker logic
425
+ * lives here (that's provider- and profile-specific, later work per
426
+ * docs/contracts/connectors.md §3); this is just the seam a daemon slot
427
+ * wires a connector through.
428
+ */
429
+ interface ConnectorRegistration {
430
+ connector: ObservedConnector;
431
+ credentials: Record<string, unknown>;
432
+ resolveTarget: ResolveConnectorTarget;
433
+ intervalMs?: number;
434
+ }
435
+
342
436
  /**
343
437
  * Multi-project daemon (ADR-049).
344
438
  *
@@ -390,6 +484,7 @@ interface DaemonOptions {
390
484
  otlpPort?: number;
391
485
  host?: string;
392
486
  bindListeners?: boolean;
487
+ connectors?: ConnectorRegistration[];
393
488
  }
394
489
  interface ProjectSlot {
395
490
  entry: RegistryEntry;
@@ -398,6 +493,7 @@ interface ProjectSlot {
398
493
  paths: ProjectPaths;
399
494
  stopPersist: () => void;
400
495
  stopStaleness: () => void;
496
+ stopConnectors: () => void;
401
497
  detachEvents: () => void;
402
498
  status: 'active' | 'broken';
403
499
  errorReason?: string;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  routeSpanToProject,
3
3
  startDaemon
4
- } from "./chunk-S7TDPQDD.js";
4
+ } from "./chunk-XV4D7A3Z.js";
5
5
  import {
6
6
  ProjectNameCollisionError,
7
7
  addProject,
@@ -37,15 +37,15 @@ import {
37
37
  thresholdForEdgeType,
38
38
  touchLastSeen,
39
39
  writeAtomically
40
- } from "./chunk-WZYH5DVG.js";
40
+ } from "./chunk-QM6BMPVJ.js";
41
41
  import {
42
42
  startOtelGrpcReceiver
43
- } from "./chunk-C5NCCKPZ.js";
43
+ } from "./chunk-UV5WSM7M.js";
44
44
  import {
45
45
  buildOtelReceiver,
46
46
  logSpanHandler,
47
47
  parseOtlpRequest
48
- } from "./chunk-2LNICOVU.js";
48
+ } from "./chunk-A3322JYS.js";
49
49
  export {
50
50
  ProjectNameCollisionError,
51
51
  addProject,