@jungjaehoon/mama-core 1.8.1 → 2.0.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/agent-graph/alias-write.js +3 -0
- package/dist/agent-graph/entity-resolve.js +3 -7
- package/dist/agent-graph/graph-query.js +5 -4
- package/dist/agent-graph/types.d.ts +30 -0
- package/dist/cases/store.d.ts +0 -4
- package/dist/cases/store.js +0 -66
- package/dist/cases/wiki-page-index.d.ts +0 -13
- package/dist/cases/wiki-page-index.js +0 -153
- package/dist/connectors/event-index.d.ts +1 -22
- package/dist/connectors/event-index.js +0 -157
- package/dist/context-compile/channel-grant.d.ts +46 -0
- package/dist/context-compile/channel-grant.js +66 -0
- package/dist/context-compile/compiler.js +5 -2
- package/dist/context-compile/index.d.ts +1 -0
- package/dist/context-compile/index.js +1 -0
- package/dist/context-compile/packet-store.d.ts +0 -1
- package/dist/context-compile/packet-store.js +0 -16
- package/dist/context-compile/source-readers.d.ts +1 -0
- package/dist/context-compile/source-readers.js +156 -23
- package/dist/context-compile/types.d.ts +17 -0
- package/dist/context-compile/visibility.js +28 -4
- package/dist/db-adapter/node-sqlite-adapter.js +4 -0
- package/dist/db-manager.d.ts +0 -13
- package/dist/db-manager.js +0 -66
- package/dist/decision-formatter.d.ts +0 -11
- package/dist/decision-formatter.js +0 -122
- package/dist/decision-tracker.d.ts +0 -12
- package/dist/decision-tracker.js +0 -50
- package/dist/edges/ref-validation.d.ts +1 -2
- package/dist/edges/ref-validation.js +33 -13
- package/dist/edges/store.d.ts +1 -3
- package/dist/edges/store.js +0 -214
- package/dist/edges/types.d.ts +10 -0
- package/dist/embedding-client.d.ts +0 -17
- package/dist/embedding-client.js +0 -80
- package/dist/embedding-server/mobile/auth.d.ts +1 -10
- package/dist/embedding-server/mobile/auth.js +0 -15
- package/dist/embeddings.d.ts +0 -12
- package/dist/embeddings.js +0 -68
- package/dist/entities/audit-metrics.d.ts +0 -5
- package/dist/entities/audit-metrics.js +0 -4
- package/dist/entities/candidate-generator.d.ts +1 -2
- package/dist/entities/candidate-generator.js +0 -412
- package/dist/entities/entity-list.d.ts +0 -1
- package/dist/entities/entity-list.js +0 -96
- package/dist/entities/entity-orphan-list.d.ts +0 -9
- package/dist/entities/entity-orphan-list.js +0 -88
- package/dist/entities/entity-search.d.ts +0 -1
- package/dist/entities/entity-search.js +0 -147
- package/dist/entities/errors.d.ts +0 -10
- package/dist/entities/errors.js +1 -25
- package/dist/entities/lineage-store.d.ts +0 -23
- package/dist/entities/lineage-store.js +0 -104
- package/dist/entities/policy-store.d.ts +0 -9
- package/dist/entities/policy-store.js +0 -188
- package/dist/entities/provenance-query.d.ts +0 -1
- package/dist/entities/provenance-query.js +0 -164
- package/dist/entities/resolution-engine.d.ts +1 -8
- package/dist/entities/resolution-engine.js +0 -66
- package/dist/entities/rollback-preview.d.ts +0 -4
- package/dist/entities/rollback-preview.js +0 -232
- package/dist/entities/store.d.ts +1 -10
- package/dist/entities/store.js +0 -49
- package/dist/index.d.ts +15 -31
- package/dist/index.js +4 -46
- package/dist/mama-api.d.ts +19 -1
- package/dist/mama-api.js +97 -2
- package/dist/memory/api.d.ts +9 -0
- package/dist/memory/api.js +68 -4
- package/dist/memory/event-store.d.ts +0 -1
- package/dist/memory/event-store.js +0 -15
- package/dist/memory/finding-store.d.ts +0 -1
- package/dist/memory/finding-store.js +0 -12
- package/dist/memory/scope-backfill.d.ts +0 -3
- package/dist/memory/scope-backfill.js +0 -74
- package/dist/memory/scope-store.d.ts +0 -1
- package/dist/memory/scope-store.js +0 -4
- package/dist/memory/truth-store.d.ts +0 -3
- package/dist/memory/truth-store.js +0 -22
- package/dist/memory/types.d.ts +0 -1
- package/dist/memory/types.js +0 -13
- package/dist/memory-store.d.ts +0 -16
- package/dist/memory-store.js +0 -51
- package/dist/ollama-client.d.ts +0 -9
- package/dist/ollama-client.js +0 -125
- package/dist/outcome-tracker.d.ts +0 -14
- package/dist/outcome-tracker.js +0 -44
- package/dist/progress-indicator.d.ts +0 -4
- package/dist/progress-indicator.js +0 -7
- package/dist/provenance/source-ref.d.ts +0 -9
- package/dist/provenance/source-ref.js +0 -145
- package/dist/query-intent.d.ts +0 -4
- package/dist/query-intent.js +0 -30
- package/dist/relevance-scorer.d.ts +0 -9
- package/dist/relevance-scorer.js +0 -81
- package/dist/search/feedback-store.d.ts +0 -1
- package/dist/search/feedback-store.js +0 -4
- package/dist/search/ranker-rescore.d.ts +0 -3
- package/dist/search/ranker-rescore.js +0 -27
- package/dist/search/ranker-trainer.d.ts +0 -8
- package/dist/search/ranker-trainer.js +0 -376
- package/dist/tier-validator.d.ts +0 -12
- package/dist/tier-validator.js +0 -56
- package/package.json +1 -10
- package/dist/cases/case-links.d.ts +0 -116
- package/dist/cases/case-links.js +0 -794
- package/dist/cases/composition-overrides.d.ts +0 -90
- package/dist/cases/composition-overrides.js +0 -724
- package/dist/cases/corrections.d.ts +0 -156
- package/dist/cases/corrections.js +0 -1045
- package/dist/cases/freshness.d.ts +0 -57
- package/dist/cases/freshness.js +0 -283
- package/dist/cases/live-state.d.ts +0 -48
- package/dist/cases/live-state.js +0 -256
- package/dist/cases/membership-explain.d.ts +0 -56
- package/dist/cases/membership-explain.js +0 -140
- package/dist/cases/membership-matcher.d.ts +0 -23
- package/dist/cases/membership-matcher.js +0 -193
- package/dist/cases/merge-split.d.ts +0 -61
- package/dist/cases/merge-split.js +0 -368
- package/dist/cases/role-inference.d.ts +0 -10
- package/dist/cases/role-inference.js +0 -85
- package/dist/cases/sqlite-transaction.d.ts +0 -10
- package/dist/cases/sqlite-transaction.js +0 -62
- package/dist/cases/target-ref.d.ts +0 -25
- package/dist/cases/target-ref.js +0 -22
- package/dist/cases/tombstone-sweeper.d.ts +0 -13
- package/dist/cases/tombstone-sweeper.js +0 -128
- package/dist/entities/entity-impact.d.ts +0 -41
- package/dist/entities/entity-impact.js +0 -140
- package/dist/entities/exact-merge-backfill.d.ts +0 -11
- package/dist/entities/exact-merge-backfill.js +0 -161
- package/dist/entities/lineage-backfill.d.ts +0 -12
- package/dist/entities/lineage-backfill.js +0 -101
- package/dist/memory-inject.d.ts +0 -24
- package/dist/memory-inject.js +0 -116
|
@@ -191,6 +191,9 @@ function attachEntityAliasWithEdge(adapter, input) {
|
|
|
191
191
|
connectors: input.connectors,
|
|
192
192
|
projectRefs: input.project_refs,
|
|
193
193
|
tenantId: input.tenant_id,
|
|
194
|
+
// source_refs are caller-supplied, so this is the surface where naming a raw id from
|
|
195
|
+
// an ungranted channel would bind it to an entity the caller can read back.
|
|
196
|
+
...(input.channels ? { channels: input.channels } : {}),
|
|
194
197
|
};
|
|
195
198
|
const sourceRefs = normalizeSourceRefs(input.source_refs);
|
|
196
199
|
if (sourceRefs.length === 0) {
|
|
@@ -168,13 +168,8 @@ function contextBoost(adapter, entityId, contextRefs, visibility, asOfMs) {
|
|
|
168
168
|
if (!contextRefs || contextRefs.length === 0) {
|
|
169
169
|
return 0;
|
|
170
170
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
connectors: visibility.connectors,
|
|
174
|
-
projectRefs: visibility.projectRefs,
|
|
175
|
-
tenantId: visibility.tenantId,
|
|
176
|
-
asOfMs,
|
|
177
|
-
});
|
|
171
|
+
// Spread rather than re-list: see graph-query's listFilteredEdges.
|
|
172
|
+
const edges = (0, ref_validation_js_1.listVisibleTwinEdgesForRefs)(adapter, contextRefs, { ...visibility, asOfMs });
|
|
178
173
|
return edges.some((edge) => (edge.subject_ref.kind === 'entity' && edge.subject_ref.id === entityId) ||
|
|
179
174
|
(edge.object_ref.kind === 'entity' && edge.object_ref.id === entityId))
|
|
180
175
|
? 0.2
|
|
@@ -189,6 +184,7 @@ function resolveEntity(adapter, input) {
|
|
|
189
184
|
projectRefs: input.project_refs,
|
|
190
185
|
tenantId: input.tenant_id,
|
|
191
186
|
asOfMs: input.as_of_ms,
|
|
187
|
+
...(input.channels ? { channels: input.channels } : {}),
|
|
192
188
|
};
|
|
193
189
|
if (input.context_refs && input.context_refs.length > 0) {
|
|
194
190
|
try {
|
|
@@ -80,11 +80,11 @@ function oppositeRef(edge, current) {
|
|
|
80
80
|
return refs;
|
|
81
81
|
}
|
|
82
82
|
function listFilteredEdges(adapter, refs, input) {
|
|
83
|
+
// Spread, not a field-by-field re-listing. Re-listing is how the channel grant was
|
|
84
|
+
// silently dropped here while every other path enforced it: a new field on the
|
|
85
|
+
// visibility type simply never arrived, and nothing failed to say so.
|
|
83
86
|
return (0, ref_validation_js_1.listVisibleTwinEdgesForRefs)(adapter, refs, {
|
|
84
|
-
|
|
85
|
-
connectors: input.visibility.connectors,
|
|
86
|
-
projectRefs: input.visibility.projectRefs,
|
|
87
|
-
tenantId: input.visibility.tenantId,
|
|
87
|
+
...input.visibility,
|
|
88
88
|
edgeTypes: input.edge_filters?.edge_types,
|
|
89
89
|
asOfMs: input.as_of_ms,
|
|
90
90
|
limit: input.limit,
|
|
@@ -104,6 +104,7 @@ function graphVisibility(input) {
|
|
|
104
104
|
connectors: input.connectors,
|
|
105
105
|
projectRefs: input.project_refs,
|
|
106
106
|
tenantId: input.tenant_id,
|
|
107
|
+
...(input.channels ? { channels: input.channels } : {}),
|
|
107
108
|
};
|
|
108
109
|
}
|
|
109
110
|
function numberMs(value, field, refId) {
|
|
@@ -10,6 +10,12 @@ export interface ResolveEntityInput {
|
|
|
10
10
|
scopes?: TwinScopeRef[];
|
|
11
11
|
connectors?: string[];
|
|
12
12
|
project_refs?: TwinProjectRef[];
|
|
13
|
+
/**
|
|
14
|
+
* Which channels of each connector may be read. Carried on every graph input for the
|
|
15
|
+
* same reason it is carried on the reader's boundary: a raw ref reached through an edge
|
|
16
|
+
* must satisfy the same rule as a row the reader would have returned.
|
|
17
|
+
*/
|
|
18
|
+
channels?: Record<string, readonly string[]>;
|
|
13
19
|
tenant_id?: string | null;
|
|
14
20
|
context_refs?: TwinRef[];
|
|
15
21
|
limit?: number;
|
|
@@ -31,6 +37,12 @@ export interface GraphNeighborhoodInput {
|
|
|
31
37
|
scopes?: TwinScopeRef[];
|
|
32
38
|
connectors?: string[];
|
|
33
39
|
project_refs?: TwinProjectRef[];
|
|
40
|
+
/**
|
|
41
|
+
* Which channels of each connector may be read. Carried on every graph input for the
|
|
42
|
+
* same reason it is carried on the reader's boundary: a raw ref reached through an edge
|
|
43
|
+
* must satisfy the same rule as a row the reader would have returned.
|
|
44
|
+
*/
|
|
45
|
+
channels?: Record<string, readonly string[]>;
|
|
34
46
|
tenant_id?: string | null;
|
|
35
47
|
edge_filters?: AgentGraphEdgeFilters;
|
|
36
48
|
as_of_ms?: number | null;
|
|
@@ -47,6 +59,12 @@ export interface GraphPathsInput {
|
|
|
47
59
|
scopes?: TwinScopeRef[];
|
|
48
60
|
connectors?: string[];
|
|
49
61
|
project_refs?: TwinProjectRef[];
|
|
62
|
+
/**
|
|
63
|
+
* Which channels of each connector may be read. Carried on every graph input for the
|
|
64
|
+
* same reason it is carried on the reader's boundary: a raw ref reached through an edge
|
|
65
|
+
* must satisfy the same rule as a row the reader would have returned.
|
|
66
|
+
*/
|
|
67
|
+
channels?: Record<string, readonly string[]>;
|
|
50
68
|
tenant_id?: string | null;
|
|
51
69
|
edge_filters?: AgentGraphEdgeFilters;
|
|
52
70
|
as_of_ms?: number | null;
|
|
@@ -64,6 +82,12 @@ export interface GraphTimelineInput {
|
|
|
64
82
|
scopes?: TwinScopeRef[];
|
|
65
83
|
connectors?: string[];
|
|
66
84
|
project_refs?: TwinProjectRef[];
|
|
85
|
+
/**
|
|
86
|
+
* Which channels of each connector may be read. Carried on every graph input for the
|
|
87
|
+
* same reason it is carried on the reader's boundary: a raw ref reached through an edge
|
|
88
|
+
* must satisfy the same rule as a row the reader would have returned.
|
|
89
|
+
*/
|
|
90
|
+
channels?: Record<string, readonly string[]>;
|
|
67
91
|
tenant_id?: string | null;
|
|
68
92
|
edge_filters?: AgentGraphEdgeFilters;
|
|
69
93
|
from_ms?: number;
|
|
@@ -153,6 +177,12 @@ export interface AttachEntityAliasWithEdgeInput {
|
|
|
153
177
|
scopes?: TwinScopeRef[];
|
|
154
178
|
connectors?: string[];
|
|
155
179
|
project_refs?: TwinProjectRef[];
|
|
180
|
+
/**
|
|
181
|
+
* Which channels of each connector may be read. Carried on every graph input for the
|
|
182
|
+
* same reason it is carried on the reader's boundary: a raw ref reached through an edge
|
|
183
|
+
* must satisfy the same rule as a row the reader would have returned.
|
|
184
|
+
*/
|
|
185
|
+
channels?: Record<string, readonly string[]>;
|
|
156
186
|
tenant_id?: string | null;
|
|
157
187
|
}
|
|
158
188
|
export interface AttachEntityAliasWithEdgeResult {
|
package/dist/cases/store.d.ts
CHANGED
|
@@ -63,10 +63,6 @@ export interface ListActiveCorrectionsForCaseResult {
|
|
|
63
63
|
*/
|
|
64
64
|
export declare function listActiveCorrectionsForCase(adapter: CaseStoreAdapter, caseId: string): ListActiveCorrectionsForCaseResult;
|
|
65
65
|
export declare function listActiveCorrectionsForCaseChain(adapter: CaseStoreAdapter, caseIds: string[]): CaseCorrectionRecord[];
|
|
66
|
-
export declare function enqueueCaseProposal(adapter: CaseStoreAdapter, input: EnqueueCaseProposalInput): {
|
|
67
|
-
proposal_id: string;
|
|
68
|
-
inserted: boolean;
|
|
69
|
-
};
|
|
70
66
|
export declare function listUnresolvedCaseProposals(adapter: CaseStoreAdapter, project: string): CaseProposalQueueRecord[];
|
|
71
67
|
export declare function assembleCase(caseId: string, options?: AssembleCaseOptions): CaseAssembly;
|
|
72
68
|
export declare function assembleCase(adapter: CaseStoreAdapter, caseId: string, options?: AssembleCaseOptions): CaseAssembly;
|
package/dist/cases/store.js
CHANGED
|
@@ -7,11 +7,8 @@ exports.upsertExplicitCaseMemberships = upsertExplicitCaseMemberships;
|
|
|
7
7
|
exports.listActiveMembershipsForCaseChain = listActiveMembershipsForCaseChain;
|
|
8
8
|
exports.listActiveCorrectionsForCase = listActiveCorrectionsForCase;
|
|
9
9
|
exports.listActiveCorrectionsForCaseChain = listActiveCorrectionsForCaseChain;
|
|
10
|
-
exports.enqueueCaseProposal = enqueueCaseProposal;
|
|
11
10
|
exports.listUnresolvedCaseProposals = listUnresolvedCaseProposals;
|
|
12
11
|
exports.assembleCase = assembleCase;
|
|
13
|
-
const node_crypto_1 = require("node:crypto");
|
|
14
|
-
const canonicalize_js_1 = require("../canonicalize.js");
|
|
15
12
|
const db_manager_js_1 = require("../db-manager.js");
|
|
16
13
|
const errors_js_1 = require("../entities/errors.js");
|
|
17
14
|
function isAdapter(value) {
|
|
@@ -447,69 +444,6 @@ function listActiveCorrectionsForCaseChain(adapter, caseIds) {
|
|
|
447
444
|
.all(...caseIds);
|
|
448
445
|
return rows.map(mapCaseCorrectionRow);
|
|
449
446
|
}
|
|
450
|
-
function isUniqueConstraintError(error) {
|
|
451
|
-
if (!(error instanceof Error)) {
|
|
452
|
-
return false;
|
|
453
|
-
}
|
|
454
|
-
return /UNIQUE constraint|SQLITE_CONSTRAINT_UNIQUE/i.test(error.message);
|
|
455
|
-
}
|
|
456
|
-
function findExistingProposalId(adapter, input, payloadFingerprint) {
|
|
457
|
-
const row = adapter
|
|
458
|
-
.prepare(`
|
|
459
|
-
SELECT proposal_id
|
|
460
|
-
FROM case_proposal_queue
|
|
461
|
-
WHERE project = ?
|
|
462
|
-
AND proposal_kind = ?
|
|
463
|
-
AND COALESCE(conflicting_case_id, '') = ?
|
|
464
|
-
AND payload_fingerprint = ?
|
|
465
|
-
AND resolved_at IS NULL
|
|
466
|
-
LIMIT 1
|
|
467
|
-
`)
|
|
468
|
-
.get(input.project, input.proposal_kind, input.conflicting_case_id ?? '', payloadFingerprint);
|
|
469
|
-
return row?.proposal_id ?? null;
|
|
470
|
-
}
|
|
471
|
-
function enqueueCaseProposal(adapter, input) {
|
|
472
|
-
const canonicalFingerprintInput = (0, canonicalize_js_1.canonicalizeJSON)(input.stable_fingerprint_input);
|
|
473
|
-
const payloadFingerprint = (0, canonicalize_js_1.targetRefHashCanonicalJSON)(canonicalFingerprintInput);
|
|
474
|
-
const proposalId = (0, node_crypto_1.randomUUID)();
|
|
475
|
-
const detectedAt = nowIso();
|
|
476
|
-
return adapter.transaction(() => {
|
|
477
|
-
try {
|
|
478
|
-
adapter
|
|
479
|
-
.prepare(`
|
|
480
|
-
INSERT INTO case_proposal_queue (
|
|
481
|
-
proposal_id, project, proposal_kind, proposed_payload, payload_fingerprint,
|
|
482
|
-
conflicting_case_id, detected_at, resolved_at, resolution, resolution_note
|
|
483
|
-
)
|
|
484
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL)
|
|
485
|
-
`)
|
|
486
|
-
.run(proposalId, input.project, input.proposal_kind, input.proposed_payload, payloadFingerprint, input.conflicting_case_id ?? null, detectedAt);
|
|
487
|
-
return { proposal_id: proposalId, inserted: true };
|
|
488
|
-
}
|
|
489
|
-
catch (error) {
|
|
490
|
-
if (!isUniqueConstraintError(error)) {
|
|
491
|
-
throw error;
|
|
492
|
-
}
|
|
493
|
-
const existingId = findExistingProposalId(adapter, input, payloadFingerprint);
|
|
494
|
-
if (!existingId) {
|
|
495
|
-
throw error;
|
|
496
|
-
}
|
|
497
|
-
// Spec §5.7 L355: re-detection updates detected_at without duplicating.
|
|
498
|
-
// Keeps listUnresolvedCaseProposals ordering (ASC detected_at) honest —
|
|
499
|
-
// recently re-detected rows move to the tail instead of sitting at
|
|
500
|
-
// stale timestamps.
|
|
501
|
-
adapter
|
|
502
|
-
.prepare(`
|
|
503
|
-
UPDATE case_proposal_queue
|
|
504
|
-
SET detected_at = ?
|
|
505
|
-
WHERE proposal_id = ?
|
|
506
|
-
AND resolved_at IS NULL
|
|
507
|
-
`)
|
|
508
|
-
.run(detectedAt, existingId);
|
|
509
|
-
return { proposal_id: existingId, inserted: false };
|
|
510
|
-
}
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
447
|
function listUnresolvedCaseProposals(adapter, project) {
|
|
514
448
|
const rows = adapter
|
|
515
449
|
.prepare(`
|
|
@@ -32,19 +32,6 @@ export interface UpsertWikiPageIndexInput {
|
|
|
32
32
|
embedding?: Float32Array | null;
|
|
33
33
|
embedding_model?: string;
|
|
34
34
|
}
|
|
35
|
-
export declare function upsertWikiPageIndexEntry(adapter: AdapterLike, input: UpsertWikiPageIndexInput): {
|
|
36
|
-
id: number;
|
|
37
|
-
created: boolean;
|
|
38
|
-
};
|
|
39
|
-
export declare function deleteWikiPageIndexEntry(adapter: AdapterLike, source_locator: string): {
|
|
40
|
-
deleted: boolean;
|
|
41
|
-
};
|
|
42
35
|
export declare function ftsSearchWikiPages(adapter: AdapterLike, query: string, limit: number): WikiPageSearchHit[];
|
|
43
36
|
export declare function vectorSearchWikiPages(adapter: AdapterLike, queryEmbedding: Float32Array, limit: number): WikiPageSearchHit[];
|
|
44
|
-
export declare function searchWikiPages(input: {
|
|
45
|
-
adapter: AdapterLike;
|
|
46
|
-
query: string;
|
|
47
|
-
queryEmbedding?: Float32Array | null;
|
|
48
|
-
limit: number;
|
|
49
|
-
}): WikiPageSearchHit[];
|
|
50
37
|
//# sourceMappingURL=wiki-page-index.d.ts.map
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.upsertWikiPageIndexEntry = upsertWikiPageIndexEntry;
|
|
7
|
-
exports.deleteWikiPageIndexEntry = deleteWikiPageIndexEntry;
|
|
8
3
|
exports.ftsSearchWikiPages = ftsSearchWikiPages;
|
|
9
4
|
exports.vectorSearchWikiPages = vectorSearchWikiPages;
|
|
10
|
-
exports.searchWikiPages = searchWikiPages;
|
|
11
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
12
5
|
const embeddings_js_1 = require("../embeddings.js");
|
|
13
6
|
function tableColumns(adapter, tableName) {
|
|
14
7
|
const rows = adapter.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
@@ -34,19 +27,12 @@ function readSchema(adapter) {
|
|
|
34
27
|
embeddingHasCreatedAt: embeddingColumns.has('created_at'),
|
|
35
28
|
};
|
|
36
29
|
}
|
|
37
|
-
function nowIso() {
|
|
38
|
-
return new Date().toISOString();
|
|
39
|
-
}
|
|
40
30
|
function normalizeLimit(limit) {
|
|
41
31
|
if (!Number.isFinite(limit)) {
|
|
42
32
|
return 10;
|
|
43
33
|
}
|
|
44
34
|
return Math.max(0, Math.floor(limit));
|
|
45
35
|
}
|
|
46
|
-
function pageIdForSourceLocator(sourceLocator) {
|
|
47
|
-
const digest = node_crypto_1.default.createHash('sha256').update(sourceLocator).digest('hex').slice(0, 24);
|
|
48
|
-
return `wiki_page_${digest}`;
|
|
49
|
-
}
|
|
50
36
|
function parseJsonArray(value) {
|
|
51
37
|
if (value === null || value === undefined || value === '') {
|
|
52
38
|
return [];
|
|
@@ -89,13 +75,6 @@ function rowToRecord(row) {
|
|
|
89
75
|
updated_at: String(row.updated_at ?? row.created_at ?? row.compiled_at ?? ''),
|
|
90
76
|
};
|
|
91
77
|
}
|
|
92
|
-
function selectByLocator(adapter, schema, sourceLocator) {
|
|
93
|
-
const sql = schema.hasIdColumn
|
|
94
|
-
? 'SELECT * FROM wiki_page_index WHERE source_locator = ?'
|
|
95
|
-
: 'SELECT rowid AS id, * FROM wiki_page_index WHERE source_locator = ?';
|
|
96
|
-
const row = adapter.prepare(sql).get(sourceLocator);
|
|
97
|
-
return row ? rowToRecord(row) : null;
|
|
98
|
-
}
|
|
99
78
|
function selectByFtsPageId(adapter, schema, pageId) {
|
|
100
79
|
const sql = schema.hasIdColumn
|
|
101
80
|
? 'SELECT * FROM wiki_page_index WHERE id = ?'
|
|
@@ -104,9 +83,6 @@ function selectByFtsPageId(adapter, schema, pageId) {
|
|
|
104
83
|
const row = adapter.prepare(sql).get(lookup);
|
|
105
84
|
return row ? rowToRecord(row) : null;
|
|
106
85
|
}
|
|
107
|
-
function vectorToBuffer(embedding) {
|
|
108
|
-
return Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
109
|
-
}
|
|
110
86
|
function blobToVector(value) {
|
|
111
87
|
if (!(value instanceof Uint8Array)) {
|
|
112
88
|
return null;
|
|
@@ -118,35 +94,6 @@ function blobToVector(value) {
|
|
|
118
94
|
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
119
95
|
return new Float32Array(arrayBuffer);
|
|
120
96
|
}
|
|
121
|
-
function upsertEmbedding(adapter, schema, record, input) {
|
|
122
|
-
if (!input.embedding) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const vector = vectorToBuffer(input.embedding);
|
|
126
|
-
const model = input.embedding_model ?? embeddings_js_1.MODEL_NAME;
|
|
127
|
-
const dim = input.embedding.length;
|
|
128
|
-
if (schema.embeddingUsesWikiPageId && schema.embeddingUsesVector) {
|
|
129
|
-
adapter
|
|
130
|
-
.prepare(`
|
|
131
|
-
INSERT INTO wiki_page_embeddings(wiki_page_id, vector, model, dim, created_at)
|
|
132
|
-
VALUES (?, ?, ?, ?, ?)
|
|
133
|
-
ON CONFLICT(wiki_page_id) DO UPDATE SET
|
|
134
|
-
vector = excluded.vector,
|
|
135
|
-
model = excluded.model,
|
|
136
|
-
dim = excluded.dim
|
|
137
|
-
`)
|
|
138
|
-
.run(record.id, vector, model, dim, nowIso());
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
adapter
|
|
142
|
-
.prepare(`
|
|
143
|
-
INSERT INTO wiki_page_embeddings(page_id, embedding)
|
|
144
|
-
VALUES (?, ?)
|
|
145
|
-
ON CONFLICT(page_id) DO UPDATE SET
|
|
146
|
-
embedding = excluded.embedding
|
|
147
|
-
`)
|
|
148
|
-
.run(pageIdForSourceLocator(record.source_locator), vector);
|
|
149
|
-
}
|
|
150
97
|
function buildFtsQuery(query) {
|
|
151
98
|
const tokens = query
|
|
152
99
|
.toLowerCase()
|
|
@@ -173,89 +120,6 @@ function searchTableExists(adapter, tableName) {
|
|
|
173
120
|
.get(tableName);
|
|
174
121
|
return row !== undefined;
|
|
175
122
|
}
|
|
176
|
-
function upsertWikiPageIndexEntry(adapter, input) {
|
|
177
|
-
const schema = readSchema(adapter);
|
|
178
|
-
const existing = selectByLocator(adapter, schema, input.source_locator);
|
|
179
|
-
const updatedAt = nowIso();
|
|
180
|
-
return adapter.transaction(() => {
|
|
181
|
-
if (schema.hasIdColumn) {
|
|
182
|
-
adapter
|
|
183
|
-
.prepare(`
|
|
184
|
-
INSERT INTO wiki_page_index (
|
|
185
|
-
source_locator, page_type, title, content, case_id, source_ids,
|
|
186
|
-
confidence, entity_refs, compiled_at, created_at, updated_at
|
|
187
|
-
)
|
|
188
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
189
|
-
ON CONFLICT(source_locator) DO UPDATE SET
|
|
190
|
-
page_type = excluded.page_type,
|
|
191
|
-
title = excluded.title,
|
|
192
|
-
content = excluded.content,
|
|
193
|
-
case_id = excluded.case_id,
|
|
194
|
-
source_ids = excluded.source_ids,
|
|
195
|
-
confidence = excluded.confidence,
|
|
196
|
-
entity_refs = excluded.entity_refs,
|
|
197
|
-
compiled_at = excluded.compiled_at,
|
|
198
|
-
updated_at = excluded.updated_at
|
|
199
|
-
`)
|
|
200
|
-
.run(input.source_locator, input.page_type, input.title, input.content, input.case_id ?? null, JSON.stringify(input.source_ids), input.confidence, JSON.stringify(input.entity_refs), input.compiled_at, updatedAt, updatedAt);
|
|
201
|
-
}
|
|
202
|
-
else if (schema.hasSourceIdsColumn && schema.hasEntityRefsColumn) {
|
|
203
|
-
adapter
|
|
204
|
-
.prepare(`
|
|
205
|
-
INSERT INTO wiki_page_index (
|
|
206
|
-
page_id, source_type, source_locator, case_id, title, page_type,
|
|
207
|
-
content, confidence, source_ids, entity_refs, compiled_at, updated_at
|
|
208
|
-
)
|
|
209
|
-
VALUES (?, 'wiki_page', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
210
|
-
ON CONFLICT(source_type, source_locator) DO UPDATE SET
|
|
211
|
-
case_id = excluded.case_id,
|
|
212
|
-
title = excluded.title,
|
|
213
|
-
page_type = excluded.page_type,
|
|
214
|
-
content = excluded.content,
|
|
215
|
-
confidence = excluded.confidence,
|
|
216
|
-
source_ids = excluded.source_ids,
|
|
217
|
-
entity_refs = excluded.entity_refs,
|
|
218
|
-
compiled_at = excluded.compiled_at,
|
|
219
|
-
updated_at = excluded.updated_at
|
|
220
|
-
`)
|
|
221
|
-
.run(pageIdForSourceLocator(input.source_locator), input.source_locator, input.case_id ?? null, input.title, input.page_type, input.content, input.confidence, JSON.stringify(input.source_ids), JSON.stringify(input.entity_refs), input.compiled_at, updatedAt);
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
adapter
|
|
225
|
-
.prepare(`
|
|
226
|
-
INSERT INTO wiki_page_index (
|
|
227
|
-
page_id, source_type, source_locator, case_id, title, page_type,
|
|
228
|
-
content, confidence, compiled_at, updated_at
|
|
229
|
-
)
|
|
230
|
-
VALUES (?, 'wiki_page', ?, ?, ?, ?, ?, ?, ?, ?)
|
|
231
|
-
ON CONFLICT(source_type, source_locator) DO UPDATE SET
|
|
232
|
-
case_id = excluded.case_id,
|
|
233
|
-
title = excluded.title,
|
|
234
|
-
page_type = excluded.page_type,
|
|
235
|
-
content = excluded.content,
|
|
236
|
-
confidence = excluded.confidence,
|
|
237
|
-
compiled_at = excluded.compiled_at,
|
|
238
|
-
updated_at = excluded.updated_at
|
|
239
|
-
`)
|
|
240
|
-
.run(pageIdForSourceLocator(input.source_locator), input.source_locator, input.case_id ?? null, input.title, input.page_type, input.content, input.confidence, input.compiled_at, updatedAt);
|
|
241
|
-
}
|
|
242
|
-
const saved = selectByLocator(adapter, schema, input.source_locator);
|
|
243
|
-
if (!saved) {
|
|
244
|
-
throw new Error(`Failed to load wiki_page_index row for ${input.source_locator}.`);
|
|
245
|
-
}
|
|
246
|
-
upsertEmbedding(adapter, schema, saved, input);
|
|
247
|
-
return {
|
|
248
|
-
id: saved.id,
|
|
249
|
-
created: existing === null,
|
|
250
|
-
};
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
function deleteWikiPageIndexEntry(adapter, source_locator) {
|
|
254
|
-
const result = adapter
|
|
255
|
-
.prepare('DELETE FROM wiki_page_index WHERE source_locator = ?')
|
|
256
|
-
.run(source_locator);
|
|
257
|
-
return { deleted: result.changes > 0 };
|
|
258
|
-
}
|
|
259
123
|
function ftsSearchWikiPages(adapter, query, limit) {
|
|
260
124
|
const boundedLimit = normalizeLimit(limit);
|
|
261
125
|
if (boundedLimit === 0 || !query.trim()) {
|
|
@@ -334,21 +198,4 @@ function vectorSearchWikiPages(adapter, queryEmbedding, limit) {
|
|
|
334
198
|
raw_score: entry.score,
|
|
335
199
|
}));
|
|
336
200
|
}
|
|
337
|
-
function searchWikiPages(input) {
|
|
338
|
-
const ftsHits = ftsSearchWikiPages(input.adapter, input.query, input.limit);
|
|
339
|
-
const vectorHits = input.queryEmbedding
|
|
340
|
-
? vectorSearchWikiPages(input.adapter, input.queryEmbedding, input.limit)
|
|
341
|
-
: [];
|
|
342
|
-
const merged = new Map();
|
|
343
|
-
for (const hit of [...ftsHits, ...vectorHits]) {
|
|
344
|
-
const existing = merged.get(hit.record.id);
|
|
345
|
-
if (!existing || hit.raw_score > existing.raw_score) {
|
|
346
|
-
merged.set(hit.record.id, hit);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
return Array.from(merged.values())
|
|
350
|
-
.sort((left, right) => right.raw_score - left.raw_score)
|
|
351
|
-
.slice(0, normalizeLimit(input.limit))
|
|
352
|
-
.map((hit, rank) => ({ ...hit, rank }));
|
|
353
|
-
}
|
|
354
201
|
//# sourceMappingURL=wiki-page-index.js.map
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
import type { DatabaseAdapter } from '../db-manager.js';
|
|
2
|
-
import type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord,
|
|
2
|
+
import type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord, UpsertConnectorEventIndexInput } from './types.js';
|
|
3
3
|
type ConnectorEventIndexAdapter = Pick<DatabaseAdapter, 'prepare' | 'transaction'>;
|
|
4
|
-
interface ListConnectorEventsByDatetimeRangeInput {
|
|
5
|
-
fromMs: number;
|
|
6
|
-
toMs: number;
|
|
7
|
-
limit?: number;
|
|
8
|
-
connectors?: string[];
|
|
9
|
-
order?: 'asc' | 'desc';
|
|
10
|
-
}
|
|
11
|
-
interface SearchConnectorEventsOptions {
|
|
12
|
-
limit?: number;
|
|
13
|
-
connectors?: string[];
|
|
14
|
-
}
|
|
15
4
|
interface DeleteExpiredConnectorEventsInput {
|
|
16
5
|
nowMs: number;
|
|
17
6
|
retentionMs: number;
|
|
18
7
|
connectorName?: string;
|
|
19
8
|
}
|
|
20
|
-
interface StalenessOptions {
|
|
21
|
-
nowMs: number;
|
|
22
|
-
staleAfterMs?: number;
|
|
23
|
-
stalenessWarnAfterMs?: number;
|
|
24
|
-
unhealthyAfterMs?: number;
|
|
25
|
-
}
|
|
26
9
|
export declare function mapConnectorEventIndexRecord(row: Record<string, unknown>): ConnectorEventIndexRecord;
|
|
27
10
|
export declare function connectorEventIndexId(sourceConnector: string, sourceId: string): string;
|
|
28
11
|
export declare function connectorEventContentHash(input: {
|
|
@@ -33,13 +16,9 @@ export declare function connectorEventContentHash(input: {
|
|
|
33
16
|
}): Buffer;
|
|
34
17
|
export declare function upsertConnectorEventIndex(adapter: ConnectorEventIndexAdapter, input: UpsertConnectorEventIndexInput): ConnectorEventIndexRecord;
|
|
35
18
|
export declare function getConnectorEventIndexRecord(adapter: ConnectorEventIndexAdapter, sourceConnector: string, sourceId: string): ConnectorEventIndexRecord | null;
|
|
36
|
-
export declare function listConnectorEventsByDatetimeRange(adapter: ConnectorEventIndexAdapter, input: ListConnectorEventsByDatetimeRangeInput): ConnectorEventIndexRecord[];
|
|
37
|
-
export declare function searchConnectorEventsByFTS(adapter: ConnectorEventIndexAdapter, query: string, options?: SearchConnectorEventsOptions): ConnectorEventSearchHit[];
|
|
38
19
|
export declare function readConnectorCursor(adapter: ConnectorEventIndexAdapter, connectorName: string): ConnectorEventIndexCursorRecord | null;
|
|
39
|
-
export declare function upsertConnectorCursor(adapter: ConnectorEventIndexAdapter, input: UpsertConnectorEventIndexCursorInput): ConnectorEventIndexCursorRecord;
|
|
40
20
|
export declare function deleteExpiredConnectorEvents(adapter: ConnectorEventIndexAdapter, input: DeleteExpiredConnectorEventsInput): {
|
|
41
21
|
rows_deleted: number;
|
|
42
22
|
};
|
|
43
|
-
export declare function computeStalenessStatus(cursor: ConnectorEventIndexCursorRecord | null, options: StalenessOptions): ConnectorEventStalenessStatus;
|
|
44
23
|
export type { ConnectorEventIndexCursorRecord, ConnectorEventIndexRecord, ConnectorEventSearchHit, ConnectorEventStalenessStatus, UpsertConnectorEventIndexCursorInput, UpsertConnectorEventIndexInput, } from './types.js';
|
|
45
24
|
//# sourceMappingURL=event-index.d.ts.map
|
|
@@ -5,32 +5,10 @@ exports.connectorEventIndexId = connectorEventIndexId;
|
|
|
5
5
|
exports.connectorEventContentHash = connectorEventContentHash;
|
|
6
6
|
exports.upsertConnectorEventIndex = upsertConnectorEventIndex;
|
|
7
7
|
exports.getConnectorEventIndexRecord = getConnectorEventIndexRecord;
|
|
8
|
-
exports.listConnectorEventsByDatetimeRange = listConnectorEventsByDatetimeRange;
|
|
9
|
-
exports.searchConnectorEventsByFTS = searchConnectorEventsByFTS;
|
|
10
8
|
exports.readConnectorCursor = readConnectorCursor;
|
|
11
|
-
exports.upsertConnectorCursor = upsertConnectorCursor;
|
|
12
9
|
exports.deleteExpiredConnectorEvents = deleteExpiredConnectorEvents;
|
|
13
|
-
exports.computeStalenessStatus = computeStalenessStatus;
|
|
14
10
|
const node_crypto_1 = require("node:crypto");
|
|
15
11
|
const canonicalize_js_1 = require("../canonicalize.js");
|
|
16
|
-
const DEFAULT_RANGE_LIMIT = 100;
|
|
17
|
-
const DEFAULT_SEARCH_LIMIT = 25;
|
|
18
|
-
const MAX_RANGE_LIMIT = 500;
|
|
19
|
-
const FIVE_MINUTES_MS = 5 * 60 * 1000;
|
|
20
|
-
const FIFTEEN_MINUTES_MS = 15 * 60 * 1000;
|
|
21
|
-
const SIXTY_MINUTES_MS = 60 * 60 * 1000;
|
|
22
|
-
function placeholders(values) {
|
|
23
|
-
if (values.length === 0) {
|
|
24
|
-
throw new Error('Cannot build SQL placeholders for an empty list.');
|
|
25
|
-
}
|
|
26
|
-
return values.map(() => '?').join(', ');
|
|
27
|
-
}
|
|
28
|
-
function positiveLimit(value, fallback, max = MAX_RANGE_LIMIT) {
|
|
29
|
-
if (value === undefined) {
|
|
30
|
-
return fallback;
|
|
31
|
-
}
|
|
32
|
-
return Math.min(max, Math.max(0, Math.floor(value)));
|
|
33
|
-
}
|
|
34
12
|
function nowIso() {
|
|
35
13
|
return new Date().toISOString();
|
|
36
14
|
}
|
|
@@ -119,16 +97,6 @@ function mapConnectorCursorRow(row) {
|
|
|
119
97
|
indexed_count: Number(row.indexed_count),
|
|
120
98
|
};
|
|
121
99
|
}
|
|
122
|
-
function connectorFilterSql(connectors, alias = '') {
|
|
123
|
-
if (!connectors || connectors.length === 0) {
|
|
124
|
-
return '';
|
|
125
|
-
}
|
|
126
|
-
const prefix = alias.length > 0 ? `${alias}.` : '';
|
|
127
|
-
return ` AND ${prefix}source_connector IN (${placeholders(connectors)})`;
|
|
128
|
-
}
|
|
129
|
-
function hasOwn(input, key) {
|
|
130
|
-
return Object.prototype.hasOwnProperty.call(input, key);
|
|
131
|
-
}
|
|
132
100
|
function connectorEventIndexId(sourceConnector, sourceId) {
|
|
133
101
|
const digest = (0, node_crypto_1.createHash)('sha1').update(`${sourceConnector}\0${sourceId}`, 'utf8').digest('hex');
|
|
134
102
|
return `evt_${digest.slice(0, 16)}`;
|
|
@@ -214,59 +182,6 @@ function getConnectorEventIndexRecord(adapter, sourceConnector, sourceId) {
|
|
|
214
182
|
.get(sourceConnector, sourceId);
|
|
215
183
|
return row ? mapConnectorEventIndexRow(row) : null;
|
|
216
184
|
}
|
|
217
|
-
function listConnectorEventsByDatetimeRange(adapter, input) {
|
|
218
|
-
const limit = positiveLimit(input.limit, DEFAULT_RANGE_LIMIT);
|
|
219
|
-
if (limit === 0) {
|
|
220
|
-
return [];
|
|
221
|
-
}
|
|
222
|
-
const order = input.order === 'desc' ? 'DESC' : 'ASC';
|
|
223
|
-
const connectors = input.connectors?.filter(Boolean) ?? [];
|
|
224
|
-
const params = [input.fromMs, input.toMs, ...connectors, limit];
|
|
225
|
-
const rows = adapter
|
|
226
|
-
.prepare(`
|
|
227
|
-
SELECT *
|
|
228
|
-
FROM connector_event_index
|
|
229
|
-
WHERE event_datetime >= ?
|
|
230
|
-
AND event_datetime <= ?
|
|
231
|
-
${connectorFilterSql(connectors)}
|
|
232
|
-
ORDER BY event_datetime ${order}, event_index_id ASC
|
|
233
|
-
LIMIT ?
|
|
234
|
-
`)
|
|
235
|
-
.all(...params);
|
|
236
|
-
return rows.map(mapConnectorEventIndexRow);
|
|
237
|
-
}
|
|
238
|
-
function searchConnectorEventsByFTS(adapter, query, options = {}) {
|
|
239
|
-
const normalizedQuery = query.trim();
|
|
240
|
-
if (normalizedQuery.length === 0) {
|
|
241
|
-
return [];
|
|
242
|
-
}
|
|
243
|
-
const limit = positiveLimit(options.limit, DEFAULT_SEARCH_LIMIT, 100);
|
|
244
|
-
if (limit === 0) {
|
|
245
|
-
return [];
|
|
246
|
-
}
|
|
247
|
-
const connectors = options.connectors?.filter(Boolean) ?? [];
|
|
248
|
-
const params = [normalizedQuery, ...connectors, limit];
|
|
249
|
-
const rows = adapter
|
|
250
|
-
.prepare(`
|
|
251
|
-
SELECT e.*, bm25(connector_event_index_fts) AS rank
|
|
252
|
-
FROM connector_event_index_fts
|
|
253
|
-
JOIN connector_event_index e
|
|
254
|
-
ON e.event_index_id = connector_event_index_fts.event_index_id
|
|
255
|
-
WHERE connector_event_index_fts MATCH ?
|
|
256
|
-
${connectorFilterSql(connectors, 'e')}
|
|
257
|
-
ORDER BY rank ASC, e.event_datetime DESC, e.event_index_id ASC
|
|
258
|
-
LIMIT ?
|
|
259
|
-
`)
|
|
260
|
-
.all(...params);
|
|
261
|
-
return rows.map((row) => {
|
|
262
|
-
const rank = Number(row.rank);
|
|
263
|
-
return {
|
|
264
|
-
...mapConnectorEventIndexRow(row),
|
|
265
|
-
rank,
|
|
266
|
-
score: Number.isFinite(rank) ? 1 / (1 + Math.exp(rank)) : 0,
|
|
267
|
-
};
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
185
|
function readConnectorCursor(adapter, connectorName) {
|
|
271
186
|
const row = adapter
|
|
272
187
|
.prepare(`
|
|
@@ -278,49 +193,6 @@ function readConnectorCursor(adapter, connectorName) {
|
|
|
278
193
|
.get(connectorName);
|
|
279
194
|
return row ? mapConnectorCursorRow(row) : null;
|
|
280
195
|
}
|
|
281
|
-
function upsertConnectorCursor(adapter, input) {
|
|
282
|
-
const current = readConnectorCursor(adapter, input.connector_name);
|
|
283
|
-
const merged = {
|
|
284
|
-
connector_name: input.connector_name,
|
|
285
|
-
last_seen_timestamp_ms: input.last_seen_timestamp_ms ?? current?.last_seen_timestamp_ms ?? 0,
|
|
286
|
-
last_seen_source_id: input.last_seen_source_id ?? current?.last_seen_source_id ?? '',
|
|
287
|
-
last_sweep_at: hasOwn(input, 'last_sweep_at')
|
|
288
|
-
? (input.last_sweep_at ?? null)
|
|
289
|
-
: (current?.last_sweep_at ?? null),
|
|
290
|
-
last_success_at: hasOwn(input, 'last_success_at')
|
|
291
|
-
? (input.last_success_at ?? null)
|
|
292
|
-
: (current?.last_success_at ?? null),
|
|
293
|
-
last_error: hasOwn(input, 'last_error')
|
|
294
|
-
? (input.last_error ?? null)
|
|
295
|
-
: (current?.last_error ?? null),
|
|
296
|
-
last_error_at: hasOwn(input, 'last_error_at')
|
|
297
|
-
? (input.last_error_at ?? null)
|
|
298
|
-
: (current?.last_error_at ?? null),
|
|
299
|
-
indexed_count: input.indexed_count ?? current?.indexed_count ?? 0,
|
|
300
|
-
};
|
|
301
|
-
adapter
|
|
302
|
-
.prepare(`
|
|
303
|
-
INSERT INTO connector_event_index_cursors (
|
|
304
|
-
connector_name, last_seen_timestamp_ms, last_seen_source_id, last_sweep_at,
|
|
305
|
-
last_success_at, last_error, last_error_at, indexed_count
|
|
306
|
-
)
|
|
307
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
308
|
-
ON CONFLICT(connector_name) DO UPDATE SET
|
|
309
|
-
last_seen_timestamp_ms = excluded.last_seen_timestamp_ms,
|
|
310
|
-
last_seen_source_id = excluded.last_seen_source_id,
|
|
311
|
-
last_sweep_at = excluded.last_sweep_at,
|
|
312
|
-
last_success_at = excluded.last_success_at,
|
|
313
|
-
last_error = excluded.last_error,
|
|
314
|
-
last_error_at = excluded.last_error_at,
|
|
315
|
-
indexed_count = excluded.indexed_count
|
|
316
|
-
`)
|
|
317
|
-
.run(merged.connector_name, merged.last_seen_timestamp_ms, merged.last_seen_source_id, merged.last_sweep_at, merged.last_success_at, merged.last_error, merged.last_error_at, merged.indexed_count);
|
|
318
|
-
const saved = readConnectorCursor(adapter, input.connector_name);
|
|
319
|
-
if (!saved) {
|
|
320
|
-
throw new Error(`Failed to read connector cursor after upsert: ${input.connector_name}`);
|
|
321
|
-
}
|
|
322
|
-
return saved;
|
|
323
|
-
}
|
|
324
196
|
function deleteExpiredConnectorEvents(adapter, input) {
|
|
325
197
|
if (!Number.isFinite(input.nowMs)) {
|
|
326
198
|
throw new Error('deleteExpiredConnectorEvents.nowMs must be a finite number.');
|
|
@@ -349,33 +221,4 @@ function deleteExpiredConnectorEvents(adapter, input) {
|
|
|
349
221
|
.run(cutoffMs);
|
|
350
222
|
return { rows_deleted: result.changes };
|
|
351
223
|
}
|
|
352
|
-
function computeStalenessStatus(cursor, options) {
|
|
353
|
-
if (!cursor) {
|
|
354
|
-
return 'never_swept';
|
|
355
|
-
}
|
|
356
|
-
if (cursor.last_error !== null) {
|
|
357
|
-
return 'unhealthy';
|
|
358
|
-
}
|
|
359
|
-
if (cursor.last_success_at === null) {
|
|
360
|
-
return 'never_swept';
|
|
361
|
-
}
|
|
362
|
-
const lastSuccessMs = Date.parse(cursor.last_success_at);
|
|
363
|
-
if (!Number.isFinite(lastSuccessMs)) {
|
|
364
|
-
return 'unhealthy';
|
|
365
|
-
}
|
|
366
|
-
const elapsedMs = options.nowMs - lastSuccessMs;
|
|
367
|
-
const staleAfterMs = options.staleAfterMs ?? FIVE_MINUTES_MS;
|
|
368
|
-
const warnAfterMs = options.stalenessWarnAfterMs ?? FIFTEEN_MINUTES_MS;
|
|
369
|
-
const unhealthyAfterMs = options.unhealthyAfterMs ?? SIXTY_MINUTES_MS;
|
|
370
|
-
if (elapsedMs > unhealthyAfterMs) {
|
|
371
|
-
return 'unhealthy';
|
|
372
|
-
}
|
|
373
|
-
if (elapsedMs > warnAfterMs) {
|
|
374
|
-
return 'warn';
|
|
375
|
-
}
|
|
376
|
-
if (elapsedMs > staleAfterMs) {
|
|
377
|
-
return 'stale-but-warming';
|
|
378
|
-
}
|
|
379
|
-
return 'healthy';
|
|
380
|
-
}
|
|
381
224
|
//# sourceMappingURL=event-index.js.map
|