claude-memory-layer 1.0.46 → 1.0.47
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/README.md +3 -2
- package/dist/cli/index.js +72 -5
- package/dist/cli/index.js.map +2 -2
- package/dist/core/index.js +1072 -4
- package/dist/core/index.js.map +4 -4
- package/dist/hooks/post-tool-use.js +71 -4
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/semantic-daemon.js +71 -4
- package/dist/hooks/semantic-daemon.js.map +2 -2
- package/dist/hooks/session-end.js +71 -4
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +71 -4
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +71 -4
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +71 -4
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/index.js +1078 -10
- package/dist/index.js.map +4 -4
- package/dist/mcp/index.js +142 -8
- package/dist/mcp/index.js.map +2 -2
- package/dist/server/api/index.js +71 -4
- package/dist/server/api/index.js.map +2 -2
- package/dist/server/index.js +71 -4
- package/dist/server/index.js.map +2 -2
- package/dist/services/memory-service.js +71 -4
- package/dist/services/memory-service.js.map +2 -2
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -2622,6 +2622,7 @@ var VectorOutbox = class {
|
|
|
2622
2622
|
// src/core/retrieval-debug-lanes.ts
|
|
2623
2623
|
var RETRIEVAL_DEBUG_LANE_NAMES = [
|
|
2624
2624
|
"raw_event",
|
|
2625
|
+
"session_event",
|
|
2625
2626
|
"session_summary",
|
|
2626
2627
|
"graph_path",
|
|
2627
2628
|
"facet_match"
|
|
@@ -11046,6 +11047,7 @@ var Retriever = class {
|
|
|
11046
11047
|
}
|
|
11047
11048
|
async retrieve(query, options = {}) {
|
|
11048
11049
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
11050
|
+
const retrievalMode = options.retrievalMode ?? ((options.strategy ?? DEFAULT_OPTIONS.strategy) === "auto" ? "session-event-hybrid" : "event");
|
|
11049
11051
|
const sessionFilter = opts.scope?.sessionId ?? opts.sessionId;
|
|
11050
11052
|
const fallbackTrace = [];
|
|
11051
11053
|
const qualityQuery = buildRetrievalQualityQuery(query);
|
|
@@ -11076,6 +11078,7 @@ var Retriever = class {
|
|
|
11076
11078
|
decayPolicy: opts.decayPolicy,
|
|
11077
11079
|
intentRewrite: opts.intentRewrite === true,
|
|
11078
11080
|
graphHop: opts.graphHop,
|
|
11081
|
+
retrievalMode,
|
|
11079
11082
|
projectScopeMode: opts.projectScopeMode,
|
|
11080
11083
|
projectHash: opts.projectHash,
|
|
11081
11084
|
allowedProjectHashes: opts.allowedProjectHashes,
|
|
@@ -11094,6 +11097,7 @@ var Retriever = class {
|
|
|
11094
11097
|
rerankWeights: opts.rerankWeights,
|
|
11095
11098
|
decayPolicy: opts.decayPolicy,
|
|
11096
11099
|
graphHop: opts.graphHop,
|
|
11100
|
+
retrievalMode,
|
|
11097
11101
|
projectScopeMode: opts.projectScopeMode,
|
|
11098
11102
|
projectHash: opts.projectHash,
|
|
11099
11103
|
allowedProjectHashes: opts.allowedProjectHashes,
|
|
@@ -11113,6 +11117,7 @@ var Retriever = class {
|
|
|
11113
11117
|
rerankWeights: opts.rerankWeights,
|
|
11114
11118
|
decayPolicy: opts.decayPolicy,
|
|
11115
11119
|
graphHop: opts.graphHop,
|
|
11120
|
+
retrievalMode,
|
|
11116
11121
|
projectScopeMode: opts.projectScopeMode,
|
|
11117
11122
|
projectHash: opts.projectHash,
|
|
11118
11123
|
allowedProjectHashes: opts.allowedProjectHashes,
|
|
@@ -11133,10 +11138,26 @@ var Retriever = class {
|
|
|
11133
11138
|
query,
|
|
11134
11139
|
minScore: opts.minScore
|
|
11135
11140
|
});
|
|
11141
|
+
const expandedSummary = retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(filteredSummary, {
|
|
11142
|
+
query: qualityQuery,
|
|
11143
|
+
currentStateQuery: query,
|
|
11144
|
+
limit: opts.topK * 4
|
|
11145
|
+
}) : filteredSummary;
|
|
11146
|
+
const scopedExpandedSummary = retrievalMode === "session-event-hybrid" ? await this.applyScopeFilters(expandedSummary, {
|
|
11147
|
+
scope: opts.scope,
|
|
11148
|
+
projectScopeMode: opts.projectScopeMode,
|
|
11149
|
+
projectHash: opts.projectHash,
|
|
11150
|
+
allowedProjectHashes: opts.allowedProjectHashes,
|
|
11151
|
+
facets: opts.facets
|
|
11152
|
+
}) : expandedSummary;
|
|
11153
|
+
const finalSummary = retrievalMode === "session-event-hybrid" ? this.applyQualityFilters(scopedExpandedSummary, {
|
|
11154
|
+
query,
|
|
11155
|
+
minScore: opts.minScore
|
|
11156
|
+
}) : scopedExpandedSummary;
|
|
11136
11157
|
current = {
|
|
11137
|
-
results:
|
|
11138
|
-
candidateResults:
|
|
11139
|
-
matchResult: this.matcher.matchSearchResults(
|
|
11158
|
+
results: finalSummary,
|
|
11159
|
+
candidateResults: finalSummary,
|
|
11160
|
+
matchResult: this.matcher.matchSearchResults(finalSummary, () => 0)
|
|
11140
11161
|
};
|
|
11141
11162
|
fallbackTrace.push("fallback:summary");
|
|
11142
11163
|
}
|
|
@@ -11222,13 +11243,18 @@ var Retriever = class {
|
|
|
11222
11243
|
initialResults = this.mergeResults(initialResults, rewrittenResults, input.topK * 3);
|
|
11223
11244
|
}
|
|
11224
11245
|
}
|
|
11225
|
-
const
|
|
11246
|
+
const graphExpandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
|
|
11226
11247
|
query,
|
|
11227
11248
|
queryGraphEnabled: this.queryGraphExpansionEnabled,
|
|
11228
11249
|
maxHops: clampGraphHops(input.graphHop?.maxHops ?? 1),
|
|
11229
11250
|
hopPenalty: Math.max(0, input.graphHop?.hopPenalty ?? 0.08),
|
|
11230
11251
|
limit: input.topK * 4
|
|
11231
11252
|
});
|
|
11253
|
+
const expandedResults = input.retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(graphExpandedResults, {
|
|
11254
|
+
query: rerankQuery,
|
|
11255
|
+
currentStateQuery: query,
|
|
11256
|
+
limit: input.topK * 4
|
|
11257
|
+
}) : graphExpandedResults;
|
|
11232
11258
|
const rerankedResults = input.rerankWithKeyword ? this.rerankByKeywordOverlap(expandedResults, rerankQuery, input.rerankWeights, input.decayPolicy) : expandedResults;
|
|
11233
11259
|
const filtered = await this.applyScopeFilters(rerankedResults, {
|
|
11234
11260
|
scope: input.scope,
|
|
@@ -11276,6 +11302,47 @@ var Retriever = class {
|
|
|
11276
11302
|
}
|
|
11277
11303
|
return [...byId.values()].sort((a, b) => b.score - a.score).slice(0, limit);
|
|
11278
11304
|
}
|
|
11305
|
+
async expandSessionEventHybrid(seeds, opts) {
|
|
11306
|
+
if (seeds.length === 0 || opts.limit <= seeds.length) return seeds;
|
|
11307
|
+
const queryTokens = this.tokenize(opts.query);
|
|
11308
|
+
if (queryTokens.length === 0) return seeds;
|
|
11309
|
+
const byId = /* @__PURE__ */ new Map();
|
|
11310
|
+
for (const seed of seeds) byId.set(seed.eventId, seed);
|
|
11311
|
+
const bestSeedBySession = /* @__PURE__ */ new Map();
|
|
11312
|
+
for (const seed of [...seeds].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId))) {
|
|
11313
|
+
if (!seed.sessionId || bestSeedBySession.has(seed.sessionId)) continue;
|
|
11314
|
+
bestSeedBySession.set(seed.sessionId, seed);
|
|
11315
|
+
}
|
|
11316
|
+
const suppressStaleState = isCurrentStateQuery(opts.currentStateQuery);
|
|
11317
|
+
for (const [sessionId, seed] of bestSeedBySession) {
|
|
11318
|
+
const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
|
|
11319
|
+
for (const event of [...sessionEvents].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())) {
|
|
11320
|
+
if (byId.has(event.id)) continue;
|
|
11321
|
+
if (isLowSignalContextContent(event.content)) continue;
|
|
11322
|
+
if (suppressStaleState && isStaleOrSupersededContent(event.content)) continue;
|
|
11323
|
+
const lexicalScore = this.keywordOverlap(queryTokens, this.tokenize(event.content));
|
|
11324
|
+
if (lexicalScore <= 0) continue;
|
|
11325
|
+
if (shouldApplyTechnicalGuard(opts.query) && !hasTechnicalTermOverlap(opts.query, event.content)) continue;
|
|
11326
|
+
const score = Math.min(0.95, Math.max(0.35, seed.score * 0.72 + lexicalScore * 0.28));
|
|
11327
|
+
const row = withRetrievalLane({
|
|
11328
|
+
id: `session-event-${seed.eventId}-${event.id}`,
|
|
11329
|
+
eventId: event.id,
|
|
11330
|
+
content: event.content,
|
|
11331
|
+
score,
|
|
11332
|
+
sessionId: event.sessionId,
|
|
11333
|
+
eventType: event.eventType,
|
|
11334
|
+
timestamp: event.timestamp.toISOString(),
|
|
11335
|
+
semanticScore: seed.semanticScore ?? seed.score,
|
|
11336
|
+
lexicalScore,
|
|
11337
|
+
recencyScore: seed.recencyScore
|
|
11338
|
+
}, { lane: "session_event", reason: `same_session:${seed.eventId}`, score });
|
|
11339
|
+
byId.set(row.eventId, row);
|
|
11340
|
+
if (byId.size >= opts.limit) break;
|
|
11341
|
+
}
|
|
11342
|
+
if (byId.size >= opts.limit) break;
|
|
11343
|
+
}
|
|
11344
|
+
return [...byId.values()].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId)).slice(0, opts.limit);
|
|
11345
|
+
}
|
|
11279
11346
|
async expandGraphHops(seeds, opts) {
|
|
11280
11347
|
const byId = /* @__PURE__ */ new Map();
|
|
11281
11348
|
for (const s of seeds) byId.set(s.eventId, s);
|
|
@@ -17286,6 +17353,985 @@ function renderProductValidationMatrixMarkdown(matrix = productValidationMatrix)
|
|
|
17286
17353
|
`;
|
|
17287
17354
|
}
|
|
17288
17355
|
|
|
17356
|
+
// src/core/source/source-schema.ts
|
|
17357
|
+
var SOURCE_PRIVACY_CLASSES = Object.freeze(["public", "internal", "confidential", "restricted"]);
|
|
17358
|
+
var SOURCE_CAPTURE_MODES = Object.freeze(["snapshot", "append-only-log", "stream", "metadata-only", "history_import"]);
|
|
17359
|
+
var SourceContractValidationError = class extends Error {
|
|
17360
|
+
violations;
|
|
17361
|
+
constructor(violations) {
|
|
17362
|
+
super(`Source contract validation failed: ${violations.map((violation2) => violation2.code).join(", ")}`);
|
|
17363
|
+
this.name = "SourceContractValidationError";
|
|
17364
|
+
this.violations = violations;
|
|
17365
|
+
}
|
|
17366
|
+
};
|
|
17367
|
+
function isSourcePrivacyClass(value) {
|
|
17368
|
+
return isOneOf(SOURCE_PRIVACY_CLASSES, value);
|
|
17369
|
+
}
|
|
17370
|
+
function isSourceCaptureMode(value) {
|
|
17371
|
+
return isOneOf(SOURCE_CAPTURE_MODES, value);
|
|
17372
|
+
}
|
|
17373
|
+
function defineSourceSchema(schema) {
|
|
17374
|
+
const prepared = prepareSourceSchema(schema);
|
|
17375
|
+
if (prepared.violations.length > 0 || !prepared.record) {
|
|
17376
|
+
throw new SourceContractValidationError(prepared.violations);
|
|
17377
|
+
}
|
|
17378
|
+
return Object.freeze(freezeSourceSchemaDeclaration(prepared.record));
|
|
17379
|
+
}
|
|
17380
|
+
function validateSourceSchema(schema, path12 = "source") {
|
|
17381
|
+
return prepareSourceSchema(schema, path12).violations;
|
|
17382
|
+
}
|
|
17383
|
+
function prepareSourceSchema(schema, path12 = "source") {
|
|
17384
|
+
const snapshot = snapshotAllowedRecordFields(schema, ["id", "version", "privacyClass", "captureMode", "description", "metadataSchema"], {
|
|
17385
|
+
path: path12,
|
|
17386
|
+
requiredCode: "source.required",
|
|
17387
|
+
requiredMessage: "Source schema declaration is required.",
|
|
17388
|
+
unknownCode: "source.unknown_field",
|
|
17389
|
+
unknownMessage: "Source schema declaration contains unsupported fields.",
|
|
17390
|
+
accessorCode: "source.accessor_field",
|
|
17391
|
+
accessorMessage: "Source schema declaration fields must be data properties."
|
|
17392
|
+
});
|
|
17393
|
+
if (!snapshot.record) return snapshot;
|
|
17394
|
+
return {
|
|
17395
|
+
record: snapshot.record,
|
|
17396
|
+
violations: validateSourceSchemaRecord(snapshot.record, path12, snapshot.violations)
|
|
17397
|
+
};
|
|
17398
|
+
}
|
|
17399
|
+
function validateSourceSchemaRecord(schema, path12, initialViolations) {
|
|
17400
|
+
const violations = [...initialViolations];
|
|
17401
|
+
const id = getOwnField(schema, "id");
|
|
17402
|
+
const version = getOwnField(schema, "version");
|
|
17403
|
+
const privacyClass = getOwnField(schema, "privacyClass");
|
|
17404
|
+
const captureMode = getOwnField(schema, "captureMode");
|
|
17405
|
+
const description = getOwnField(schema, "description");
|
|
17406
|
+
const metadataSchema = getOwnField(schema, "metadataSchema");
|
|
17407
|
+
if (!hasText(id)) {
|
|
17408
|
+
violations.push(violation("source.id.required", `${path12}.id`, "Source schema id must be non-empty."));
|
|
17409
|
+
} else {
|
|
17410
|
+
if (!isStableContractIdentifier(id)) {
|
|
17411
|
+
violations.push(violation("source.id.unstable", `${path12}.id`, "Source schema id must be stable and must not include a local absolute path."));
|
|
17412
|
+
}
|
|
17413
|
+
if (looksLikePrivacySensitiveSourceValue(id)) {
|
|
17414
|
+
violations.push(violation("source.id.privacy_sensitive", `${path12}.id`, "Source schema id must not leak local state handles or credential-shaped values."));
|
|
17415
|
+
}
|
|
17416
|
+
}
|
|
17417
|
+
if (!hasText(version)) {
|
|
17418
|
+
violations.push(violation("source.version.required", `${path12}.version`, "Source schema version must be non-empty."));
|
|
17419
|
+
} else if (looksLikePrivacySensitiveSourceValue(version)) {
|
|
17420
|
+
violations.push(violation("source.version.privacy_sensitive", `${path12}.version`, "Source schema version must not leak local state handles or credential-shaped values."));
|
|
17421
|
+
}
|
|
17422
|
+
if (!isSourcePrivacyClass(privacyClass)) {
|
|
17423
|
+
violations.push(violation("source.privacyClass.invalid", `${path12}.privacyClass`, "Source schema privacyClass must be one of the bounded source privacy classes."));
|
|
17424
|
+
}
|
|
17425
|
+
if (!isSourceCaptureMode(captureMode)) {
|
|
17426
|
+
violations.push(violation("source.captureMode.invalid", `${path12}.captureMode`, "Source schema captureMode must be one of the bounded source capture modes."));
|
|
17427
|
+
}
|
|
17428
|
+
if (description !== void 0 && typeof description !== "string") {
|
|
17429
|
+
violations.push(violation("source.description.invalid", `${path12}.description`, "Source schema description must be a string when present."));
|
|
17430
|
+
} else if (hasText(description) && looksLikePrivacySensitiveSourceValue(description)) {
|
|
17431
|
+
violations.push(violation("source.description.privacy_sensitive", `${path12}.description`, "Source schema description must not leak local state handles or credential-shaped values."));
|
|
17432
|
+
}
|
|
17433
|
+
if (metadataSchema !== void 0 && typeof metadataSchema !== "string") {
|
|
17434
|
+
violations.push(violation("source.metadataSchema.invalid", `${path12}.metadataSchema`, "Source schema metadataSchema must be a string when present."));
|
|
17435
|
+
} else if (hasText(metadataSchema) && looksLikePrivacySensitiveSourceValue(metadataSchema)) {
|
|
17436
|
+
violations.push(violation("source.metadataSchema.privacy_sensitive", `${path12}.metadataSchema`, "Source schema metadataSchema must not leak local state handles or credential-shaped values."));
|
|
17437
|
+
}
|
|
17438
|
+
return violations;
|
|
17439
|
+
}
|
|
17440
|
+
function freezeSourceSchemaDeclaration(schema) {
|
|
17441
|
+
const id = getOwnField(schema, "id");
|
|
17442
|
+
const version = getOwnField(schema, "version");
|
|
17443
|
+
const privacyClass = getOwnField(schema, "privacyClass");
|
|
17444
|
+
const captureMode = getOwnField(schema, "captureMode");
|
|
17445
|
+
const ownDescription = getOwnField(schema, "description");
|
|
17446
|
+
const ownMetadataSchema = getOwnField(schema, "metadataSchema");
|
|
17447
|
+
const defined = {
|
|
17448
|
+
id,
|
|
17449
|
+
version,
|
|
17450
|
+
privacyClass,
|
|
17451
|
+
captureMode
|
|
17452
|
+
};
|
|
17453
|
+
if (ownDescription !== void 0) defined.description = ownDescription;
|
|
17454
|
+
if (ownMetadataSchema !== void 0) defined.metadataSchema = ownMetadataSchema;
|
|
17455
|
+
return defined;
|
|
17456
|
+
}
|
|
17457
|
+
function hasText(value) {
|
|
17458
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
17459
|
+
}
|
|
17460
|
+
function isArrayForSourceSnapshot(value) {
|
|
17461
|
+
try {
|
|
17462
|
+
return Array.isArray(value);
|
|
17463
|
+
} catch {
|
|
17464
|
+
return false;
|
|
17465
|
+
}
|
|
17466
|
+
}
|
|
17467
|
+
function isRecord6(value) {
|
|
17468
|
+
return typeof value === "object" && value !== null && !isArrayForSourceSnapshot(value);
|
|
17469
|
+
}
|
|
17470
|
+
function hasOwnField(record, key) {
|
|
17471
|
+
return Object.prototype.hasOwnProperty.call(record, key);
|
|
17472
|
+
}
|
|
17473
|
+
function getOwnField(record, key) {
|
|
17474
|
+
try {
|
|
17475
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
17476
|
+
return descriptor && "value" in descriptor ? descriptor.value : void 0;
|
|
17477
|
+
} catch {
|
|
17478
|
+
return void 0;
|
|
17479
|
+
}
|
|
17480
|
+
}
|
|
17481
|
+
function safeOwnKeysForSourceSnapshot(value, path12, code, message) {
|
|
17482
|
+
try {
|
|
17483
|
+
return { keys: Reflect.ownKeys(value), violations: [] };
|
|
17484
|
+
} catch {
|
|
17485
|
+
return { keys: [], violations: [violation(code, path12, message)] };
|
|
17486
|
+
}
|
|
17487
|
+
}
|
|
17488
|
+
function safeGetOwnPropertyDescriptorForSourceSnapshot(value, key, path12, code, message) {
|
|
17489
|
+
try {
|
|
17490
|
+
return { descriptor: Object.getOwnPropertyDescriptor(value, key), violations: [] };
|
|
17491
|
+
} catch {
|
|
17492
|
+
return { violations: [violation(code, path12, message)] };
|
|
17493
|
+
}
|
|
17494
|
+
}
|
|
17495
|
+
function safeReadOwnDataPropertyForSourceSnapshot(value, key, descriptor, path12, code, message) {
|
|
17496
|
+
if (!("value" in descriptor)) {
|
|
17497
|
+
return { violations: [violation(code, path12, message)] };
|
|
17498
|
+
}
|
|
17499
|
+
try {
|
|
17500
|
+
const readValue = Reflect.get(value, key, value);
|
|
17501
|
+
if (!Object.is(readValue, descriptor.value)) {
|
|
17502
|
+
return { violations: [violation(code, path12, message)] };
|
|
17503
|
+
}
|
|
17504
|
+
return { value: descriptor.value, violations: [] };
|
|
17505
|
+
} catch {
|
|
17506
|
+
return { violations: [violation(code, path12, message)] };
|
|
17507
|
+
}
|
|
17508
|
+
}
|
|
17509
|
+
function snapshotAllowedRecordFields(value, allowedFields, options) {
|
|
17510
|
+
if (!isRecord6(value)) {
|
|
17511
|
+
return {
|
|
17512
|
+
record: void 0,
|
|
17513
|
+
violations: [violation(options.requiredCode, options.path, options.requiredMessage)]
|
|
17514
|
+
};
|
|
17515
|
+
}
|
|
17516
|
+
const allowed = new Set(allowedFields);
|
|
17517
|
+
const record = /* @__PURE__ */ Object.create(null);
|
|
17518
|
+
const keySnapshot = safeOwnKeysForSourceSnapshot(value, options.path, options.accessorCode, options.accessorMessage);
|
|
17519
|
+
const violations = [...keySnapshot.violations];
|
|
17520
|
+
for (const key of keySnapshot.keys) {
|
|
17521
|
+
if (typeof key !== "string" || !allowed.has(key)) {
|
|
17522
|
+
violations.push(violation(options.unknownCode, options.path, options.unknownMessage));
|
|
17523
|
+
continue;
|
|
17524
|
+
}
|
|
17525
|
+
const descriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(value, key, `${options.path}.${key}`, options.accessorCode, options.accessorMessage);
|
|
17526
|
+
violations.push(...descriptorSnapshot.violations);
|
|
17527
|
+
const descriptor = descriptorSnapshot.descriptor;
|
|
17528
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
17529
|
+
violations.push(violation(options.accessorCode, `${options.path}.${key}`, options.accessorMessage));
|
|
17530
|
+
continue;
|
|
17531
|
+
}
|
|
17532
|
+
const readSnapshot = safeReadOwnDataPropertyForSourceSnapshot(value, key, descriptor, `${options.path}.${key}`, options.accessorCode, options.accessorMessage);
|
|
17533
|
+
violations.push(...readSnapshot.violations);
|
|
17534
|
+
if (readSnapshot.violations.length > 0) continue;
|
|
17535
|
+
record[key] = readSnapshot.value;
|
|
17536
|
+
}
|
|
17537
|
+
return { record, violations };
|
|
17538
|
+
}
|
|
17539
|
+
function isStableContractIdentifier(value) {
|
|
17540
|
+
if (!hasText(value)) return false;
|
|
17541
|
+
if (looksLikeLocalAbsolutePath(value)) return false;
|
|
17542
|
+
return /^[A-Za-z0-9][A-Za-z0-9._:@-]*$/.test(value);
|
|
17543
|
+
}
|
|
17544
|
+
function looksLikeLocalAbsolutePath(value) {
|
|
17545
|
+
const trimmed = value.trim();
|
|
17546
|
+
if (trimmed.length === 0) return false;
|
|
17547
|
+
return sourceValueVariants(trimmed).some((candidate) => {
|
|
17548
|
+
const normalized = candidate.replace(/\\/g, "/");
|
|
17549
|
+
return /^file:\/*/i.test(normalized) || /[A-Za-z]:\//.test(normalized) || normalized.startsWith("/") || /(?:^|[^A-Za-z0-9])file:\/*/i.test(normalized) || /(?:^|[^A-Za-z0-9])\/(?!\/)/.test(normalized) || /(?:^|[^A-Za-z0-9])(?:Users|home|root|tmp|var|data)(?:\/|$)/.test(normalized) || /(?:^|\/(?:\/*))(?:Users|home|root|tmp|var|data)(?:\/|$)/.test(normalized) || /(?:^|[^A-Za-z0-9])\\\\/.test(candidate);
|
|
17550
|
+
});
|
|
17551
|
+
}
|
|
17552
|
+
function looksLikePrivacySensitiveSourceValue(value, fieldName = "") {
|
|
17553
|
+
if (typeof value !== "string") return false;
|
|
17554
|
+
const trimmed = value.trim();
|
|
17555
|
+
if (trimmed.length === 0) return false;
|
|
17556
|
+
return sourceValueVariants(trimmed).some((candidate) => {
|
|
17557
|
+
const normalized = candidate.replace(/\\/g, "/");
|
|
17558
|
+
return looksLikeLocalAbsolutePath(candidate) || /(?:^|[\s:=,;|()[\]{}<>"'`])~(?:\/|$)/.test(normalized) || /(?:^|\/)\.hermes(?:\/|$)/i.test(normalized) || /(?:^|[^A-Za-z0-9])state\.db(?:$|[^A-Za-z0-9])/i.test(normalized) || looksLikeCredentialAssignment(candidate) || looksLikeBareCredentialToken(candidate) || looksLikeCredentialFieldValue(fieldName, candidate) || /\bBearer\s+(?!\[?redacted\]?(?:$|[\s&;,|()[\]{}<>"'`]))[A-Za-z0-9._~+/=-]{3,}/i.test(candidate) || /(?:^|[\s:=,;|()[\]{}<>"'`])[a-z][a-z0-9+.-]*:\/\/[^\s/@:]+:[^\s/@]+@/i.test(candidate) || /(?:^|[\s:=,;|()[\]{}<>"'`])[a-z][a-z0-9+.-]*:\/\/:[^\s/@]+@/i.test(candidate);
|
|
17559
|
+
});
|
|
17560
|
+
}
|
|
17561
|
+
function violation(code, path12, message) {
|
|
17562
|
+
return { code, path: path12, message };
|
|
17563
|
+
}
|
|
17564
|
+
function looksLikeCredentialAssignment(value) {
|
|
17565
|
+
return /(?:^|[^A-Za-z0-9_-])(?:api[_-]?key|access[_-]?token|auth[_-]?token|client[_-]?secret|secret|password|passwd|authorization|token)\s*[:=]\s*(?!(?:Bearer\s+)?\[?redacted\]?(?:$|[\s&;,|()[\]{}<>"'`]))(?:Bearer\s+)?[^\s&;,|]{3,}/i.test(value);
|
|
17566
|
+
}
|
|
17567
|
+
function looksLikeBareCredentialToken(value) {
|
|
17568
|
+
if (/^\[?redacted\]?$/i.test(value.trim())) return false;
|
|
17569
|
+
const tokenBoundary = "(?:^|[^A-Za-z0-9_-])";
|
|
17570
|
+
const tokenEnd = "(?:$|[^A-Za-z0-9_-])";
|
|
17571
|
+
return [
|
|
17572
|
+
new RegExp(`${tokenBoundary}sk[-_][A-Za-z0-9][A-Za-z0-9_-]{2,}${tokenEnd}`),
|
|
17573
|
+
new RegExp(`${tokenBoundary}gh[a-z]_[A-Za-z0-9_]{3,}${tokenEnd}`),
|
|
17574
|
+
new RegExp(`${tokenBoundary}github_pat_[A-Za-z0-9_]{3,}${tokenEnd}`),
|
|
17575
|
+
new RegExp(`${tokenBoundary}xox[abprs]-[A-Za-z0-9-]{3,}${tokenEnd}`),
|
|
17576
|
+
new RegExp(`${tokenBoundary}hf_[A-Za-z0-9]{3,}${tokenEnd}`),
|
|
17577
|
+
new RegExp(`${tokenBoundary}glpat-[A-Za-z0-9_-]{3,}${tokenEnd}`),
|
|
17578
|
+
new RegExp(`${tokenBoundary}(?:AKIA|ASIA)[A-Z0-9]{8,}${tokenEnd}`),
|
|
17579
|
+
new RegExp(`${tokenBoundary}AIza[A-Za-z0-9_-]{3,}${tokenEnd}`),
|
|
17580
|
+
new RegExp(`${tokenBoundary}eyJ[A-Za-z0-9_-]*.[A-Za-z0-9_-]{3,}.[A-Za-z0-9_-]{3,}${tokenEnd}`)
|
|
17581
|
+
].some((pattern) => pattern.test(value));
|
|
17582
|
+
}
|
|
17583
|
+
function sourceValueVariants(value) {
|
|
17584
|
+
const variants = /* @__PURE__ */ new Set([value]);
|
|
17585
|
+
let current = value;
|
|
17586
|
+
for (let attempt = 0; attempt < 5 && current.includes("%"); attempt += 1) {
|
|
17587
|
+
const decoded = decodePercentEncodedBestEffort(current);
|
|
17588
|
+
if (decoded === current) break;
|
|
17589
|
+
variants.add(decoded);
|
|
17590
|
+
current = decoded;
|
|
17591
|
+
}
|
|
17592
|
+
return [...variants];
|
|
17593
|
+
}
|
|
17594
|
+
function decodePercentEncodedBestEffort(value) {
|
|
17595
|
+
try {
|
|
17596
|
+
return decodeURIComponent(value);
|
|
17597
|
+
} catch {
|
|
17598
|
+
return value.replace(/%[0-9A-Fa-f]{2}/g, (match) => String.fromCharCode(Number.parseInt(match.slice(1), 16)));
|
|
17599
|
+
}
|
|
17600
|
+
}
|
|
17601
|
+
function looksLikeCredentialFieldValue(fieldName, value) {
|
|
17602
|
+
return /^(?:api[_-]?key|access[_-]?token|auth[_-]?token|client[_-]?secret|secret|password|passwd|authorization|token)$/i.test(fieldName.trim()) && !/^\[?redacted\]?$/i.test(value.trim());
|
|
17603
|
+
}
|
|
17604
|
+
function isOneOf(values, value) {
|
|
17605
|
+
return typeof value === "string" && values.includes(value);
|
|
17606
|
+
}
|
|
17607
|
+
|
|
17608
|
+
// src/core/source/source-ref.ts
|
|
17609
|
+
function createSourceRef(ref) {
|
|
17610
|
+
const prepared = prepareSourceRef(ref);
|
|
17611
|
+
if (prepared.violations.length > 0 || !prepared.record) {
|
|
17612
|
+
throw new SourceContractValidationError(prepared.violations);
|
|
17613
|
+
}
|
|
17614
|
+
const kind = getOwnField(prepared.record, "kind");
|
|
17615
|
+
const stableId = getOwnField(prepared.record, "stableId");
|
|
17616
|
+
const publicHandle = getOwnField(prepared.record, "publicHandle");
|
|
17617
|
+
const evidenceHandle = getOwnField(prepared.record, "evidenceHandle");
|
|
17618
|
+
const privacyClass = getOwnField(prepared.record, "privacyClass");
|
|
17619
|
+
const captureMode = getOwnField(prepared.record, "captureMode");
|
|
17620
|
+
return Object.freeze({
|
|
17621
|
+
kind,
|
|
17622
|
+
stableId,
|
|
17623
|
+
publicHandle,
|
|
17624
|
+
...evidenceHandle !== void 0 ? { evidenceHandle } : {},
|
|
17625
|
+
privacyClass,
|
|
17626
|
+
captureMode,
|
|
17627
|
+
...prepared.metadata !== void 0 ? { metadata: prepared.metadata } : {}
|
|
17628
|
+
});
|
|
17629
|
+
}
|
|
17630
|
+
function validateSourceRef(ref, path12 = "sourceRef") {
|
|
17631
|
+
return prepareSourceRef(ref, path12).violations;
|
|
17632
|
+
}
|
|
17633
|
+
function prepareSourceRef(ref, path12 = "sourceRef") {
|
|
17634
|
+
const snapshot = snapshotAllowedRecordFields(ref, ["kind", "stableId", "publicHandle", "evidenceHandle", "privacyClass", "captureMode", "metadata"], {
|
|
17635
|
+
path: path12,
|
|
17636
|
+
requiredCode: "sourceRef.required",
|
|
17637
|
+
requiredMessage: "Source ref is required.",
|
|
17638
|
+
unknownCode: "sourceRef.unknown_field",
|
|
17639
|
+
unknownMessage: "Source ref contains unsupported fields.",
|
|
17640
|
+
accessorCode: "sourceRef.accessor_field",
|
|
17641
|
+
accessorMessage: "Source ref fields must be data properties."
|
|
17642
|
+
});
|
|
17643
|
+
if (!snapshot.record) {
|
|
17644
|
+
return { violations: snapshot.violations };
|
|
17645
|
+
}
|
|
17646
|
+
const violations = [...snapshot.violations];
|
|
17647
|
+
const kind = getOwnField(snapshot.record, "kind");
|
|
17648
|
+
const stableId = getOwnField(snapshot.record, "stableId");
|
|
17649
|
+
const publicHandle = getOwnField(snapshot.record, "publicHandle");
|
|
17650
|
+
const evidenceHandle = getOwnField(snapshot.record, "evidenceHandle");
|
|
17651
|
+
const privacyClass = getOwnField(snapshot.record, "privacyClass");
|
|
17652
|
+
const captureMode = getOwnField(snapshot.record, "captureMode");
|
|
17653
|
+
const metadata = getOwnField(snapshot.record, "metadata");
|
|
17654
|
+
if (!hasText(kind)) {
|
|
17655
|
+
violations.push(violation("sourceRef.kind.required", `${path12}.kind`, "Source ref kind must be non-empty."));
|
|
17656
|
+
} else if (looksLikePrivacySensitiveSourceValue(kind)) {
|
|
17657
|
+
violations.push(violation("sourceRef.kind.privacy_sensitive", `${path12}.kind`, "Source ref kind must not leak local state handles or credential-shaped values."));
|
|
17658
|
+
}
|
|
17659
|
+
if (!hasText(stableId)) {
|
|
17660
|
+
violations.push(violation("sourceRef.stableId.required", `${path12}.stableId`, "Source ref stableId must be non-empty."));
|
|
17661
|
+
} else {
|
|
17662
|
+
if (looksLikeLocalAbsolutePath(stableId)) {
|
|
17663
|
+
violations.push(violation("sourceRef.stableId.absolute_local_path", `${path12}.stableId`, "Source ref stableId must not be a local absolute path."));
|
|
17664
|
+
}
|
|
17665
|
+
if (looksLikePrivacySensitiveSourceValue(stableId)) {
|
|
17666
|
+
violations.push(violation("sourceRef.stableId.privacy_sensitive", `${path12}.stableId`, "Source ref stableId must not leak local state handles or credential-shaped values."));
|
|
17667
|
+
}
|
|
17668
|
+
}
|
|
17669
|
+
validatePublicHandle(publicHandle, `${path12}.publicHandle`, violations);
|
|
17670
|
+
validateEvidenceHandle(evidenceHandle, `${path12}.evidenceHandle`, violations);
|
|
17671
|
+
if (!isSourcePrivacyClass(privacyClass)) {
|
|
17672
|
+
violations.push(violation("sourceRef.privacyClass.invalid", `${path12}.privacyClass`, "Source ref privacyClass must be one of the bounded source privacy classes."));
|
|
17673
|
+
}
|
|
17674
|
+
if (!isSourceCaptureMode(captureMode)) {
|
|
17675
|
+
violations.push(violation("sourceRef.captureMode.invalid", `${path12}.captureMode`, "Source ref captureMode must be one of the bounded source capture modes."));
|
|
17676
|
+
}
|
|
17677
|
+
const metadataSnapshot = snapshotSourceRefMetadata(metadata, `${path12}.metadata`);
|
|
17678
|
+
violations.push(...metadataSnapshot.violations);
|
|
17679
|
+
return {
|
|
17680
|
+
record: snapshot.record,
|
|
17681
|
+
metadata: metadataSnapshot.record,
|
|
17682
|
+
violations
|
|
17683
|
+
};
|
|
17684
|
+
}
|
|
17685
|
+
function validatePublicHandle(value, path12, violations) {
|
|
17686
|
+
if (!hasText(value)) {
|
|
17687
|
+
violations.push(violation("sourceRef.publicHandle.required", path12, "Source ref publicHandle must be non-empty."));
|
|
17688
|
+
return;
|
|
17689
|
+
}
|
|
17690
|
+
if (looksLikeLocalAbsolutePath(value)) {
|
|
17691
|
+
violations.push(violation("sourceRef.publicHandle.absolute_local_path", path12, "Source ref publicHandle must not leak a local absolute path."));
|
|
17692
|
+
}
|
|
17693
|
+
if (looksLikePrivacySensitiveSourceValue(value)) {
|
|
17694
|
+
violations.push(violation("sourceRef.publicHandle.privacy_sensitive", path12, "Source ref publicHandle must not leak local state handles or credential-shaped values."));
|
|
17695
|
+
}
|
|
17696
|
+
}
|
|
17697
|
+
function validateEvidenceHandle(value, path12, violations) {
|
|
17698
|
+
if (value === void 0) return;
|
|
17699
|
+
if (!hasText(value)) {
|
|
17700
|
+
violations.push(violation("sourceRef.evidenceHandle.invalid", path12, "Source ref evidenceHandle must be a non-empty string when present."));
|
|
17701
|
+
return;
|
|
17702
|
+
}
|
|
17703
|
+
if (looksLikeLocalAbsolutePath(value)) {
|
|
17704
|
+
violations.push(violation("sourceRef.evidenceHandle.absolute_local_path", path12, "Source ref evidenceHandle must not leak a local absolute path."));
|
|
17705
|
+
}
|
|
17706
|
+
if (looksLikePrivacySensitiveSourceValue(value)) {
|
|
17707
|
+
violations.push(violation("sourceRef.evidenceHandle.privacy_sensitive", path12, "Source ref evidenceHandle must not leak local state handles or credential-shaped values."));
|
|
17708
|
+
}
|
|
17709
|
+
}
|
|
17710
|
+
function snapshotSourceRefMetadata(metadata, path12) {
|
|
17711
|
+
if (metadata === void 0) return { violations: [] };
|
|
17712
|
+
if (!isRecord6(metadata)) {
|
|
17713
|
+
return {
|
|
17714
|
+
violations: [violation("sourceRef.metadata.invalid", path12, "Source ref metadata must be an object when present.")]
|
|
17715
|
+
};
|
|
17716
|
+
}
|
|
17717
|
+
const snapshot = /* @__PURE__ */ Object.create(null);
|
|
17718
|
+
const keySnapshot = safeOwnKeysForSourceSnapshot(metadata, path12, "sourceRef.metadata.accessor_field", "Source ref metadata values must be data properties.");
|
|
17719
|
+
const violations = [...keySnapshot.violations];
|
|
17720
|
+
keySnapshot.keys.forEach((key, index) => {
|
|
17721
|
+
if (typeof key !== "string") {
|
|
17722
|
+
const valuePath2 = `${path12}.[symbol-${index}]`;
|
|
17723
|
+
violations.push(violation("sourceRef.metadata.invalid_key", valuePath2, "Source ref metadata keys must be strings."));
|
|
17724
|
+
const descriptorSnapshot2 = safeGetOwnPropertyDescriptorForSourceSnapshot(metadata, key, valuePath2, "sourceRef.metadata.accessor_field", "Source ref metadata values must be data properties.");
|
|
17725
|
+
violations.push(...descriptorSnapshot2.violations);
|
|
17726
|
+
const descriptor2 = descriptorSnapshot2.descriptor;
|
|
17727
|
+
if (!descriptor2 || !("value" in descriptor2)) {
|
|
17728
|
+
violations.push(violation("sourceRef.metadata.accessor_field", valuePath2, "Source ref metadata values must be data properties."));
|
|
17729
|
+
return;
|
|
17730
|
+
}
|
|
17731
|
+
const readSnapshot2 = safeReadOwnDataPropertyForSourceSnapshot(metadata, key, descriptor2, valuePath2, "sourceRef.metadata.accessor_field", "Source ref metadata values must be data properties.");
|
|
17732
|
+
violations.push(...readSnapshot2.violations);
|
|
17733
|
+
if (readSnapshot2.violations.length > 0) return;
|
|
17734
|
+
validateMetadataValue(readSnapshot2.value, valuePath2, propertyKeyDescription(key), violations);
|
|
17735
|
+
return;
|
|
17736
|
+
}
|
|
17737
|
+
const valuePath = metadataEntryPath(path12, key, index);
|
|
17738
|
+
if (looksLikePrivacySensitiveSourceValue(key)) {
|
|
17739
|
+
violations.push(violation("sourceRef.metadata.privacy_sensitive", valuePath, "Source ref metadata keys must not leak local state handles or credential-shaped values."));
|
|
17740
|
+
}
|
|
17741
|
+
const descriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(metadata, key, valuePath, "sourceRef.metadata.accessor_field", "Source ref metadata values must be data properties.");
|
|
17742
|
+
violations.push(...descriptorSnapshot.violations);
|
|
17743
|
+
const descriptor = descriptorSnapshot.descriptor;
|
|
17744
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
17745
|
+
violations.push(violation("sourceRef.metadata.accessor_field", valuePath, "Source ref metadata values must be data properties."));
|
|
17746
|
+
return;
|
|
17747
|
+
}
|
|
17748
|
+
const readSnapshot = safeReadOwnDataPropertyForSourceSnapshot(metadata, key, descriptor, valuePath, "sourceRef.metadata.accessor_field", "Source ref metadata values must be data properties.");
|
|
17749
|
+
violations.push(...readSnapshot.violations);
|
|
17750
|
+
if (readSnapshot.violations.length > 0) return;
|
|
17751
|
+
validateMetadataValue(readSnapshot.value, valuePath, key, violations);
|
|
17752
|
+
if (isSourceRefMetadataValue(readSnapshot.value)) {
|
|
17753
|
+
snapshot[key] = readSnapshot.value;
|
|
17754
|
+
}
|
|
17755
|
+
});
|
|
17756
|
+
return { record: Object.freeze(snapshot), violations };
|
|
17757
|
+
}
|
|
17758
|
+
function isSourceRefMetadataValue(value) {
|
|
17759
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
17760
|
+
}
|
|
17761
|
+
function validateMetadataValue(value, valuePath, key, violations) {
|
|
17762
|
+
if (value === null) return;
|
|
17763
|
+
if (typeof value === "number") {
|
|
17764
|
+
if (!Number.isFinite(value)) {
|
|
17765
|
+
violations.push(violation("sourceRef.metadata.invalid_value", valuePath, "Source ref metadata numbers must be finite."));
|
|
17766
|
+
}
|
|
17767
|
+
if (looksLikePrivacySensitiveSourceValue(String(value), key)) {
|
|
17768
|
+
violations.push(violation("sourceRef.metadata.privacy_sensitive", valuePath, "Source ref metadata must not leak local state handles or credential-shaped values."));
|
|
17769
|
+
}
|
|
17770
|
+
return;
|
|
17771
|
+
}
|
|
17772
|
+
if (typeof value === "boolean") {
|
|
17773
|
+
if (looksLikePrivacySensitiveSourceValue(String(value), key)) {
|
|
17774
|
+
violations.push(violation("sourceRef.metadata.privacy_sensitive", valuePath, "Source ref metadata must not leak local state handles or credential-shaped values."));
|
|
17775
|
+
}
|
|
17776
|
+
return;
|
|
17777
|
+
}
|
|
17778
|
+
if (typeof value === "string") {
|
|
17779
|
+
if (looksLikePrivacySensitiveSourceValue(value, key)) {
|
|
17780
|
+
violations.push(violation("sourceRef.metadata.privacy_sensitive", valuePath, "Source ref metadata must not leak local state handles or credential-shaped values."));
|
|
17781
|
+
}
|
|
17782
|
+
return;
|
|
17783
|
+
}
|
|
17784
|
+
violations.push(violation("sourceRef.metadata.invalid_value", valuePath, "Source ref metadata values must be scalar strings, finite numbers, booleans, or null."));
|
|
17785
|
+
}
|
|
17786
|
+
function propertyKeyDescription(key) {
|
|
17787
|
+
return typeof key === "symbol" ? String(key.description ?? "") : "";
|
|
17788
|
+
}
|
|
17789
|
+
function metadataEntryPath(path12, key, index) {
|
|
17790
|
+
if (looksLikePrivacySensitiveSourceValue(key)) {
|
|
17791
|
+
return `${path12}.[redacted-key-${index}]`;
|
|
17792
|
+
}
|
|
17793
|
+
const sanitizedKey = key.replace(/[^A-Za-z0-9._:-]+/g, "_").slice(0, 64);
|
|
17794
|
+
return sanitizedKey ? `${path12}.${sanitizedKey}` : `${path12}.${index}`;
|
|
17795
|
+
}
|
|
17796
|
+
|
|
17797
|
+
// src/core/source/source-transformations.ts
|
|
17798
|
+
var MAX_SOURCE_TRANSFORMATION_DECLARATIONS = 1e3;
|
|
17799
|
+
var SOURCE_TRANSFORMATION_KINDS = Object.freeze(["extract", "normalize", "privacy-filter", "map", "enrich"]);
|
|
17800
|
+
function isSourceTransformationKind(value) {
|
|
17801
|
+
return typeof value === "string" && SOURCE_TRANSFORMATION_KINDS.includes(value);
|
|
17802
|
+
}
|
|
17803
|
+
function defineSourceTransformation(transformation) {
|
|
17804
|
+
const prepared = prepareSourceTransformationDeclaration(transformation);
|
|
17805
|
+
if (prepared.violations.length > 0 || !prepared.record) {
|
|
17806
|
+
throw new SourceContractValidationError(prepared.violations);
|
|
17807
|
+
}
|
|
17808
|
+
return Object.freeze(freezeSourceTransformationDeclaration(prepared.record));
|
|
17809
|
+
}
|
|
17810
|
+
function defineSourceTransformations(transformations) {
|
|
17811
|
+
const prepared = prepareSourceTransformationDeclarations(transformations, "transformations");
|
|
17812
|
+
if (prepared.violations.length > 0) {
|
|
17813
|
+
throw new SourceContractValidationError(prepared.violations);
|
|
17814
|
+
}
|
|
17815
|
+
return Object.freeze(prepared.records.map((transformation) => Object.freeze(freezeSourceTransformationDeclaration(transformation))));
|
|
17816
|
+
}
|
|
17817
|
+
function validateSourceTransformationDeclarations(transformations, path12 = "transformations") {
|
|
17818
|
+
return prepareSourceTransformationDeclarations(transformations, path12).violations;
|
|
17819
|
+
}
|
|
17820
|
+
function prepareSourceTransformationDeclarations(transformations, path12) {
|
|
17821
|
+
const snapshot = snapshotSourceTransformationArray(transformations, path12);
|
|
17822
|
+
const violations = [...snapshot.violations];
|
|
17823
|
+
const records = [];
|
|
17824
|
+
for (let index = 0; index < snapshot.items.length; index += 1) {
|
|
17825
|
+
const prepared = prepareSourceTransformationDeclaration(snapshot.items[index], `${path12}.${index}`);
|
|
17826
|
+
violations.push(...prepared.violations);
|
|
17827
|
+
if (prepared.record) records[index] = prepared.record;
|
|
17828
|
+
}
|
|
17829
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
17830
|
+
for (const transformation of records) {
|
|
17831
|
+
if (!isRecord6(transformation)) continue;
|
|
17832
|
+
const id = getOwnField(transformation, "id");
|
|
17833
|
+
if (!hasText(id)) continue;
|
|
17834
|
+
if (seenIds.has(id)) {
|
|
17835
|
+
violations.push(violation("transformation.id.duplicate", path12, "Duplicate transformation id."));
|
|
17836
|
+
}
|
|
17837
|
+
seenIds.add(id);
|
|
17838
|
+
}
|
|
17839
|
+
return { records, violations };
|
|
17840
|
+
}
|
|
17841
|
+
function snapshotSourceTransformationArray(transformations, path12) {
|
|
17842
|
+
if (!isArrayForSourceSnapshot(transformations)) {
|
|
17843
|
+
return {
|
|
17844
|
+
items: [],
|
|
17845
|
+
violations: [violation("transformations.required", path12, "At least one source transformation declaration is required.")]
|
|
17846
|
+
};
|
|
17847
|
+
}
|
|
17848
|
+
const lengthDescriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(
|
|
17849
|
+
transformations,
|
|
17850
|
+
"length",
|
|
17851
|
+
path12,
|
|
17852
|
+
"transformations.length.invalid",
|
|
17853
|
+
"Source transformation declarations must expose a stable bounded array length."
|
|
17854
|
+
);
|
|
17855
|
+
if (lengthDescriptorSnapshot.violations.length > 0) {
|
|
17856
|
+
return { items: [], violations: lengthDescriptorSnapshot.violations };
|
|
17857
|
+
}
|
|
17858
|
+
const lengthDescriptor = lengthDescriptorSnapshot.descriptor;
|
|
17859
|
+
if (!lengthDescriptor || !("value" in lengthDescriptor)) {
|
|
17860
|
+
return {
|
|
17861
|
+
items: [],
|
|
17862
|
+
violations: [violation("transformations.length.invalid", path12, "Source transformation declarations must expose a stable bounded array length.")]
|
|
17863
|
+
};
|
|
17864
|
+
}
|
|
17865
|
+
const lengthReadSnapshot = safeReadOwnDataPropertyForSourceSnapshot(
|
|
17866
|
+
transformations,
|
|
17867
|
+
"length",
|
|
17868
|
+
lengthDescriptor,
|
|
17869
|
+
path12,
|
|
17870
|
+
"transformations.length.invalid",
|
|
17871
|
+
"Source transformation declarations must expose a stable bounded array length."
|
|
17872
|
+
);
|
|
17873
|
+
if (lengthReadSnapshot.violations.length > 0) {
|
|
17874
|
+
return { items: [], violations: lengthReadSnapshot.violations };
|
|
17875
|
+
}
|
|
17876
|
+
const length = lengthReadSnapshot.value;
|
|
17877
|
+
if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0 || length > MAX_SOURCE_TRANSFORMATION_DECLARATIONS) {
|
|
17878
|
+
return {
|
|
17879
|
+
items: [],
|
|
17880
|
+
violations: [violation("transformations.length.invalid", path12, "Source transformation declarations must expose a stable bounded array length.")]
|
|
17881
|
+
};
|
|
17882
|
+
}
|
|
17883
|
+
if (length === 0) {
|
|
17884
|
+
return {
|
|
17885
|
+
items: [],
|
|
17886
|
+
violations: [violation("transformations.required", path12, "At least one source transformation declaration is required.")]
|
|
17887
|
+
};
|
|
17888
|
+
}
|
|
17889
|
+
const items = new Array(length);
|
|
17890
|
+
const violations = [];
|
|
17891
|
+
for (let index = 0; index < length; index += 1) {
|
|
17892
|
+
const itemPath = `${path12}.${index}`;
|
|
17893
|
+
const descriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(
|
|
17894
|
+
transformations,
|
|
17895
|
+
String(index),
|
|
17896
|
+
itemPath,
|
|
17897
|
+
"transformations.accessor_field",
|
|
17898
|
+
"Source transformation declaration array entries must be data properties."
|
|
17899
|
+
);
|
|
17900
|
+
violations.push(...descriptorSnapshot.violations);
|
|
17901
|
+
const descriptor = descriptorSnapshot.descriptor;
|
|
17902
|
+
if (!descriptor) {
|
|
17903
|
+
violations.push(violation("transformations.missing_index", itemPath, "Source transformation declarations must be a dense array."));
|
|
17904
|
+
continue;
|
|
17905
|
+
}
|
|
17906
|
+
if (!("value" in descriptor)) {
|
|
17907
|
+
violations.push(violation("transformations.accessor_field", itemPath, "Source transformation declaration array entries must be data properties."));
|
|
17908
|
+
continue;
|
|
17909
|
+
}
|
|
17910
|
+
const readSnapshot = safeReadOwnDataPropertyForSourceSnapshot(
|
|
17911
|
+
transformations,
|
|
17912
|
+
String(index),
|
|
17913
|
+
descriptor,
|
|
17914
|
+
itemPath,
|
|
17915
|
+
"transformations.accessor_field",
|
|
17916
|
+
"Source transformation declaration array entries must be data properties."
|
|
17917
|
+
);
|
|
17918
|
+
violations.push(...readSnapshot.violations);
|
|
17919
|
+
if (readSnapshot.violations.length > 0) continue;
|
|
17920
|
+
items[index] = readSnapshot.value;
|
|
17921
|
+
}
|
|
17922
|
+
return { items, violations };
|
|
17923
|
+
}
|
|
17924
|
+
function validateSourceTransformationDeclaration(transformation, path12 = "transformation") {
|
|
17925
|
+
return prepareSourceTransformationDeclaration(transformation, path12).violations;
|
|
17926
|
+
}
|
|
17927
|
+
function prepareSourceTransformationDeclaration(transformation, path12 = "transformation") {
|
|
17928
|
+
const snapshot = snapshotAllowedRecordFields(transformation, ["id", "version", "kind", "inputSchema", "outputSchema", "deterministic", "description"], {
|
|
17929
|
+
path: path12,
|
|
17930
|
+
requiredCode: "transformation.required",
|
|
17931
|
+
requiredMessage: "Source transformation declaration is required.",
|
|
17932
|
+
unknownCode: "transformation.unknown_field",
|
|
17933
|
+
unknownMessage: "Source transformation declaration contains unsupported fields.",
|
|
17934
|
+
accessorCode: "transformation.accessor_field",
|
|
17935
|
+
accessorMessage: "Source transformation declaration fields must be data properties."
|
|
17936
|
+
});
|
|
17937
|
+
if (!snapshot.record) return { violations: snapshot.violations };
|
|
17938
|
+
const violations = [...snapshot.violations];
|
|
17939
|
+
const id = getOwnField(snapshot.record, "id");
|
|
17940
|
+
const version = getOwnField(snapshot.record, "version");
|
|
17941
|
+
const kind = getOwnField(snapshot.record, "kind");
|
|
17942
|
+
const inputSchema = getOwnField(snapshot.record, "inputSchema");
|
|
17943
|
+
const outputSchema = getOwnField(snapshot.record, "outputSchema");
|
|
17944
|
+
const deterministic = getOwnField(snapshot.record, "deterministic");
|
|
17945
|
+
const description = getOwnField(snapshot.record, "description");
|
|
17946
|
+
if (!hasText(id)) {
|
|
17947
|
+
violations.push(violation("transformation.id.required", `${path12}.id`, "Source transformation id must be non-empty."));
|
|
17948
|
+
} else {
|
|
17949
|
+
if (!isStableContractIdentifier(id)) {
|
|
17950
|
+
violations.push(violation("transformation.id.unstable", `${path12}.id`, "Source transformation id must be stable and must not include a local absolute path."));
|
|
17951
|
+
}
|
|
17952
|
+
if (looksLikePrivacySensitiveSourceValue(id)) {
|
|
17953
|
+
violations.push(violation("transformation.id.privacy_sensitive", `${path12}.id`, "Source transformation id must not leak local state handles or credential-shaped values."));
|
|
17954
|
+
}
|
|
17955
|
+
}
|
|
17956
|
+
if (!hasText(version)) {
|
|
17957
|
+
violations.push(violation("transformation.version.required", `${path12}.version`, "Source transformation version must be non-empty."));
|
|
17958
|
+
} else if (looksLikePrivacySensitiveSourceValue(version)) {
|
|
17959
|
+
violations.push(violation("transformation.version.privacy_sensitive", `${path12}.version`, "Source transformation version must not leak local state handles or credential-shaped values."));
|
|
17960
|
+
}
|
|
17961
|
+
if (!isSourceTransformationKind(kind)) {
|
|
17962
|
+
violations.push(violation("transformation.kind.invalid", `${path12}.kind`, "Source transformation kind must be one of the bounded source transformation kinds."));
|
|
17963
|
+
}
|
|
17964
|
+
if (!hasText(inputSchema)) {
|
|
17965
|
+
violations.push(violation("transformation.inputSchema.required", `${path12}.inputSchema`, "Source transformation inputSchema must be non-empty."));
|
|
17966
|
+
} else if (looksLikePrivacySensitiveSourceValue(inputSchema)) {
|
|
17967
|
+
violations.push(violation("transformation.inputSchema.privacy_sensitive", `${path12}.inputSchema`, "Source transformation inputSchema must not leak local state handles or credential-shaped values."));
|
|
17968
|
+
}
|
|
17969
|
+
if (!hasText(outputSchema)) {
|
|
17970
|
+
violations.push(violation("transformation.outputSchema.required", `${path12}.outputSchema`, "Source transformation outputSchema must be non-empty."));
|
|
17971
|
+
} else if (looksLikePrivacySensitiveSourceValue(outputSchema)) {
|
|
17972
|
+
violations.push(violation("transformation.outputSchema.privacy_sensitive", `${path12}.outputSchema`, "Source transformation outputSchema must not leak local state handles or credential-shaped values."));
|
|
17973
|
+
}
|
|
17974
|
+
if (deterministic !== void 0 && typeof deterministic !== "boolean") {
|
|
17975
|
+
violations.push(violation("transformation.deterministic.invalid", `${path12}.deterministic`, "Source transformation deterministic must be a boolean when present."));
|
|
17976
|
+
}
|
|
17977
|
+
if (description !== void 0 && typeof description !== "string") {
|
|
17978
|
+
violations.push(violation("transformation.description.invalid", `${path12}.description`, "Source transformation description must be a string when present."));
|
|
17979
|
+
} else if (hasText(description) && looksLikePrivacySensitiveSourceValue(description)) {
|
|
17980
|
+
violations.push(violation("transformation.description.privacy_sensitive", `${path12}.description`, "Source transformation description must not leak local state handles or credential-shaped values."));
|
|
17981
|
+
}
|
|
17982
|
+
return { record: snapshot.record, violations };
|
|
17983
|
+
}
|
|
17984
|
+
function freezeSourceTransformationDeclaration(transformation) {
|
|
17985
|
+
const id = getOwnField(transformation, "id");
|
|
17986
|
+
const version = getOwnField(transformation, "version");
|
|
17987
|
+
const kind = getOwnField(transformation, "kind");
|
|
17988
|
+
const inputSchema = getOwnField(transformation, "inputSchema");
|
|
17989
|
+
const outputSchema = getOwnField(transformation, "outputSchema");
|
|
17990
|
+
const deterministic = getOwnField(transformation, "deterministic");
|
|
17991
|
+
const description = getOwnField(transformation, "description");
|
|
17992
|
+
const defined = {
|
|
17993
|
+
id,
|
|
17994
|
+
version,
|
|
17995
|
+
kind,
|
|
17996
|
+
inputSchema,
|
|
17997
|
+
outputSchema
|
|
17998
|
+
};
|
|
17999
|
+
if (deterministic !== void 0) defined.deterministic = deterministic;
|
|
18000
|
+
if (description !== void 0) defined.description = description;
|
|
18001
|
+
return defined;
|
|
18002
|
+
}
|
|
18003
|
+
|
|
18004
|
+
// src/core/source/source-adapter.ts
|
|
18005
|
+
function validateSourceAdapterIdentity(identity, path12 = "identity") {
|
|
18006
|
+
return prepareSourceAdapterIdentity(identity, path12).violations;
|
|
18007
|
+
}
|
|
18008
|
+
function prepareSourceAdapterIdentity(identity, path12 = "identity") {
|
|
18009
|
+
const snapshot = snapshotAllowedRecordFields(identity, ["id", "version", "displayName"], {
|
|
18010
|
+
path: path12,
|
|
18011
|
+
requiredCode: "identity.required",
|
|
18012
|
+
requiredMessage: "Source adapter identity is required.",
|
|
18013
|
+
unknownCode: "identity.unknown_field",
|
|
18014
|
+
unknownMessage: "Source adapter contract object contains unsupported fields.",
|
|
18015
|
+
accessorCode: "identity.accessor_field",
|
|
18016
|
+
accessorMessage: "Source adapter identity fields must be data properties."
|
|
18017
|
+
});
|
|
18018
|
+
if (!snapshot.record) return { violations: snapshot.violations };
|
|
18019
|
+
const violations = [...snapshot.violations];
|
|
18020
|
+
const id = getOwnField(snapshot.record, "id");
|
|
18021
|
+
const version = getOwnField(snapshot.record, "version");
|
|
18022
|
+
const displayName = getOwnField(snapshot.record, "displayName");
|
|
18023
|
+
if (!hasText(id)) {
|
|
18024
|
+
violations.push(violation("identity.id.required", `${path12}.id`, "Source adapter identity id must be non-empty."));
|
|
18025
|
+
} else {
|
|
18026
|
+
if (!isStableContractIdentifier(id)) {
|
|
18027
|
+
violations.push(violation("identity.id.unstable", `${path12}.id`, "Source adapter identity id must be stable and must not include a local absolute path."));
|
|
18028
|
+
}
|
|
18029
|
+
if (looksLikePrivacySensitiveSourceValue(id)) {
|
|
18030
|
+
violations.push(violation("identity.id.privacy_sensitive", `${path12}.id`, "Source adapter identity id must not leak local state handles or credential-shaped values."));
|
|
18031
|
+
}
|
|
18032
|
+
}
|
|
18033
|
+
if (!hasText(version)) {
|
|
18034
|
+
violations.push(violation("identity.version.required", `${path12}.version`, "Source adapter identity version must be non-empty."));
|
|
18035
|
+
} else if (looksLikePrivacySensitiveSourceValue(version)) {
|
|
18036
|
+
violations.push(violation("identity.version.privacy_sensitive", `${path12}.version`, "Source adapter identity version must not leak local state handles or credential-shaped values."));
|
|
18037
|
+
}
|
|
18038
|
+
if (displayName !== void 0 && typeof displayName !== "string") {
|
|
18039
|
+
violations.push(violation("identity.displayName.invalid", `${path12}.displayName`, "Source adapter displayName must be a string when present."));
|
|
18040
|
+
} else if (hasText(displayName) && looksLikePrivacySensitiveSourceValue(displayName)) {
|
|
18041
|
+
violations.push(violation("identity.displayName.privacy_sensitive", `${path12}.displayName`, "Source adapter displayName must not leak local state handles or credential-shaped values."));
|
|
18042
|
+
}
|
|
18043
|
+
return { record: snapshot.record, violations };
|
|
18044
|
+
}
|
|
18045
|
+
function freezeSourceAdapterIdentity(identity) {
|
|
18046
|
+
const id = getOwnField(identity, "id");
|
|
18047
|
+
const version = getOwnField(identity, "version");
|
|
18048
|
+
const displayName = getOwnField(identity, "displayName");
|
|
18049
|
+
const defined = {
|
|
18050
|
+
id,
|
|
18051
|
+
version
|
|
18052
|
+
};
|
|
18053
|
+
if (displayName !== void 0) defined.displayName = displayName;
|
|
18054
|
+
return Object.freeze(defined);
|
|
18055
|
+
}
|
|
18056
|
+
function validateSourceAdapterCapabilities(capabilities, path12 = "capabilities") {
|
|
18057
|
+
return prepareSourceAdapterCapabilities(capabilities, path12).violations;
|
|
18058
|
+
}
|
|
18059
|
+
function prepareSourceAdapterCapabilities(capabilities, path12 = "capabilities") {
|
|
18060
|
+
if (!isRecord6(capabilities)) {
|
|
18061
|
+
return {
|
|
18062
|
+
violations: [violation("capabilities.required", path12, "Source adapter capabilities with currentnessStrategy are required.")]
|
|
18063
|
+
};
|
|
18064
|
+
}
|
|
18065
|
+
const record = /* @__PURE__ */ Object.create(null);
|
|
18066
|
+
const keySnapshot = safeOwnKeysForSourceSnapshot(capabilities, path12, "capabilities.accessor_field", "Source adapter capability fields must be data properties.");
|
|
18067
|
+
const violations = [...keySnapshot.violations];
|
|
18068
|
+
keySnapshot.keys.forEach((key, index) => {
|
|
18069
|
+
if (typeof key !== "string") {
|
|
18070
|
+
const valuePath2 = `${path12}.[symbol-${index}]`;
|
|
18071
|
+
violations.push(violation("capabilities.invalid_key", valuePath2, "Source adapter capability keys must be strings."));
|
|
18072
|
+
const descriptorSnapshot2 = safeGetOwnPropertyDescriptorForSourceSnapshot(capabilities, key, valuePath2, "capabilities.accessor_field", "Source adapter capability fields must be data properties.");
|
|
18073
|
+
violations.push(...descriptorSnapshot2.violations);
|
|
18074
|
+
const descriptor2 = descriptorSnapshot2.descriptor;
|
|
18075
|
+
if (!descriptor2 || !("value" in descriptor2)) {
|
|
18076
|
+
violations.push(violation("capabilities.accessor_field", valuePath2, "Source adapter capability fields must be data properties."));
|
|
18077
|
+
return;
|
|
18078
|
+
}
|
|
18079
|
+
const readSnapshot2 = safeReadOwnDataPropertyForSourceSnapshot(capabilities, key, descriptor2, valuePath2, "capabilities.accessor_field", "Source adapter capability fields must be data properties.");
|
|
18080
|
+
violations.push(...readSnapshot2.violations);
|
|
18081
|
+
if (readSnapshot2.violations.length > 0) return;
|
|
18082
|
+
validateCapabilityValue(propertyKeyDescription2(key), readSnapshot2.value, valuePath2, violations);
|
|
18083
|
+
return;
|
|
18084
|
+
}
|
|
18085
|
+
const valuePath = capabilityEntryPath(path12, key, index);
|
|
18086
|
+
const descriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(capabilities, key, valuePath, "capabilities.accessor_field", "Source adapter capability fields must be data properties.");
|
|
18087
|
+
violations.push(...descriptorSnapshot.violations);
|
|
18088
|
+
const descriptor = descriptorSnapshot.descriptor;
|
|
18089
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
18090
|
+
violations.push(violation("capabilities.accessor_field", valuePath, "Source adapter capability fields must be data properties."));
|
|
18091
|
+
return;
|
|
18092
|
+
}
|
|
18093
|
+
const readSnapshot = safeReadOwnDataPropertyForSourceSnapshot(capabilities, key, descriptor, valuePath, "capabilities.accessor_field", "Source adapter capability fields must be data properties.");
|
|
18094
|
+
violations.push(...readSnapshot.violations);
|
|
18095
|
+
if (readSnapshot.violations.length > 0) return;
|
|
18096
|
+
record[key] = readSnapshot.value;
|
|
18097
|
+
validateCapabilityValue(key, readSnapshot.value, valuePath, violations);
|
|
18098
|
+
});
|
|
18099
|
+
const currentnessStrategy = getOwnField(record, "currentnessStrategy");
|
|
18100
|
+
if (!hasOwnField(record, "currentnessStrategy") || !hasText(currentnessStrategy)) {
|
|
18101
|
+
violations.push(violation("capabilities.currentnessStrategy.required", `${path12}.currentnessStrategy`, "Source adapter capabilities must declare a deterministic currentnessStrategy."));
|
|
18102
|
+
} else if (!isStableContractIdentifier(currentnessStrategy)) {
|
|
18103
|
+
violations.push(violation("capabilities.currentnessStrategy.unstable", `${path12}.currentnessStrategy`, "Source adapter currentnessStrategy must be stable and must not include a local absolute path."));
|
|
18104
|
+
}
|
|
18105
|
+
return { record, violations };
|
|
18106
|
+
}
|
|
18107
|
+
function freezeSourceAdapterCapabilities(capabilities) {
|
|
18108
|
+
const keySnapshot = safeOwnKeysForSourceSnapshot(capabilities, "capabilities", "capabilities.accessor_field", "Source adapter capability fields must be data properties.");
|
|
18109
|
+
const safeEntries = [];
|
|
18110
|
+
keySnapshot.keys.forEach((key) => {
|
|
18111
|
+
if (typeof key !== "string") return;
|
|
18112
|
+
const descriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(capabilities, key, `capabilities.${key}`, "capabilities.accessor_field", "Source adapter capability fields must be data properties.");
|
|
18113
|
+
const descriptor = descriptorSnapshot.descriptor;
|
|
18114
|
+
if (descriptor && "value" in descriptor) safeEntries.push([key, descriptor.value]);
|
|
18115
|
+
});
|
|
18116
|
+
return Object.freeze(Object.fromEntries(safeEntries));
|
|
18117
|
+
}
|
|
18118
|
+
function propertyKeyDescription2(key) {
|
|
18119
|
+
return typeof key === "symbol" ? String(key.description ?? "") : "";
|
|
18120
|
+
}
|
|
18121
|
+
function capabilityEntryPath(path12, key, index) {
|
|
18122
|
+
if (looksLikePrivacySensitiveSourceValue(key)) {
|
|
18123
|
+
return `${path12}.[redacted-key-${index}]`;
|
|
18124
|
+
}
|
|
18125
|
+
const sanitizedKey = key.replace(/[^A-Za-z0-9._:-]+/g, "_").slice(0, 64);
|
|
18126
|
+
return sanitizedKey ? `${path12}.${sanitizedKey}` : `${path12}.${index}`;
|
|
18127
|
+
}
|
|
18128
|
+
function validateCapabilityValue(key, value, path12, violations) {
|
|
18129
|
+
if (looksLikePrivacySensitiveSourceValue(key)) {
|
|
18130
|
+
violations.push(violation("capabilities.privacy_sensitive", path12, "Source adapter capability keys must not leak local state handles or credential-shaped values."));
|
|
18131
|
+
}
|
|
18132
|
+
if (typeof value === "number") {
|
|
18133
|
+
if (!Number.isFinite(value)) {
|
|
18134
|
+
violations.push(violation("capabilities.invalid_value", path12, "Source adapter capability numbers must be finite."));
|
|
18135
|
+
}
|
|
18136
|
+
if (looksLikePrivacySensitiveSourceValue(String(value), key)) {
|
|
18137
|
+
violations.push(violation("capabilities.privacy_sensitive", path12, "Source adapter capability values must not leak local state handles or credential-shaped values."));
|
|
18138
|
+
}
|
|
18139
|
+
return;
|
|
18140
|
+
}
|
|
18141
|
+
if (typeof value === "boolean") return;
|
|
18142
|
+
if (typeof value === "string") {
|
|
18143
|
+
if (looksLikePrivacySensitiveSourceValue(value, key)) {
|
|
18144
|
+
violations.push(violation("capabilities.privacy_sensitive", path12, "Source adapter capability values must not leak local state handles or credential-shaped values."));
|
|
18145
|
+
}
|
|
18146
|
+
return;
|
|
18147
|
+
}
|
|
18148
|
+
violations.push(violation("capabilities.invalid_value", path12, "Source adapter capability values must be scalar strings, finite numbers, or booleans."));
|
|
18149
|
+
}
|
|
18150
|
+
|
|
18151
|
+
// src/core/source/source-adapter-contract-suite.ts
|
|
18152
|
+
var MAX_SAMPLE_SOURCE_REFS = 1e3;
|
|
18153
|
+
function validateSourceAdapterContract(adapter, path12 = "adapter") {
|
|
18154
|
+
return prepareSourceAdapterContract(adapter, path12).violations;
|
|
18155
|
+
}
|
|
18156
|
+
function assertSourceAdapterContract(adapter) {
|
|
18157
|
+
return defineSourceAdapter(adapter);
|
|
18158
|
+
}
|
|
18159
|
+
function defineSourceAdapter(adapter) {
|
|
18160
|
+
const prepared = prepareSourceAdapterContract(adapter);
|
|
18161
|
+
if (prepared.violations.length > 0 || !prepared.contract) {
|
|
18162
|
+
throw new SourceContractValidationError(prepared.violations);
|
|
18163
|
+
}
|
|
18164
|
+
return Object.freeze(prepared.contract);
|
|
18165
|
+
}
|
|
18166
|
+
function prepareSourceAdapterContract(adapter, path12 = "adapter") {
|
|
18167
|
+
const snapshot = snapshotAllowedRecordFields(adapter, ["identity", "source", "transformations", "sampleSourceRefs", "capabilities"], {
|
|
18168
|
+
path: path12,
|
|
18169
|
+
requiredCode: "adapter.required",
|
|
18170
|
+
requiredMessage: "Source adapter contract is required.",
|
|
18171
|
+
unknownCode: "adapter.unknown_field",
|
|
18172
|
+
unknownMessage: "Source adapter contract contains unsupported fields.",
|
|
18173
|
+
accessorCode: "adapter.accessor_field",
|
|
18174
|
+
accessorMessage: "Source adapter contract fields must be data properties."
|
|
18175
|
+
});
|
|
18176
|
+
if (!snapshot.record) return { violations: snapshot.violations };
|
|
18177
|
+
const violations = [...snapshot.violations];
|
|
18178
|
+
const identityInput = getOwnField(snapshot.record, "identity");
|
|
18179
|
+
const sourceInput = getOwnField(snapshot.record, "source");
|
|
18180
|
+
const transformationsInput = getOwnField(snapshot.record, "transformations");
|
|
18181
|
+
const capabilitiesInput = getOwnField(snapshot.record, "capabilities");
|
|
18182
|
+
const sampleSourceRefsInput = getOwnField(snapshot.record, "sampleSourceRefs");
|
|
18183
|
+
const identityPrepared = prepareSourceAdapterIdentity(identityInput, `${path12}.identity`);
|
|
18184
|
+
violations.push(...identityPrepared.violations);
|
|
18185
|
+
const sourcePrepared = defineSafeResult(
|
|
18186
|
+
() => defineSourceSchema(sourceInput),
|
|
18187
|
+
"source",
|
|
18188
|
+
`${path12}.source`,
|
|
18189
|
+
"source.validation_error",
|
|
18190
|
+
"Source schema validation failed unexpectedly."
|
|
18191
|
+
);
|
|
18192
|
+
violations.push(...sourcePrepared.violations);
|
|
18193
|
+
const transformationsPrepared = defineSafeResult(
|
|
18194
|
+
() => defineSourceTransformations(transformationsInput),
|
|
18195
|
+
"transformations",
|
|
18196
|
+
`${path12}.transformations`,
|
|
18197
|
+
"transformations.validation_error",
|
|
18198
|
+
"Source transformation validation failed unexpectedly."
|
|
18199
|
+
);
|
|
18200
|
+
violations.push(...transformationsPrepared.violations);
|
|
18201
|
+
const capabilitiesPrepared = prepareSourceAdapterCapabilities(capabilitiesInput, `${path12}.capabilities`);
|
|
18202
|
+
violations.push(...capabilitiesPrepared.violations);
|
|
18203
|
+
const sampleSourceRefsPrepared = defineSampleSourceRefs(sampleSourceRefsInput, `${path12}.sampleSourceRefs`);
|
|
18204
|
+
violations.push(...sampleSourceRefsPrepared.violations);
|
|
18205
|
+
if (violations.length > 0 || !identityPrepared.record || !sourcePrepared.value || !transformationsPrepared.value || !capabilitiesPrepared.record) {
|
|
18206
|
+
return { violations };
|
|
18207
|
+
}
|
|
18208
|
+
const contract = {
|
|
18209
|
+
identity: freezeSourceAdapterIdentity(identityPrepared.record),
|
|
18210
|
+
source: sourcePrepared.value,
|
|
18211
|
+
transformations: transformationsPrepared.value,
|
|
18212
|
+
sampleSourceRefs: sampleSourceRefsPrepared.value,
|
|
18213
|
+
capabilities: freezeSourceAdapterCapabilities(capabilitiesPrepared.record)
|
|
18214
|
+
};
|
|
18215
|
+
return { contract, violations };
|
|
18216
|
+
}
|
|
18217
|
+
function defineSampleSourceRefs(sampleSourceRefs, path12) {
|
|
18218
|
+
if (sampleSourceRefs === void 0) return { violations: [] };
|
|
18219
|
+
if (!isArrayForSourceSnapshot(sampleSourceRefs)) {
|
|
18220
|
+
return {
|
|
18221
|
+
violations: [violation("sampleSourceRefs.invalid", path12, "sampleSourceRefs must be an array when present.")]
|
|
18222
|
+
};
|
|
18223
|
+
}
|
|
18224
|
+
const snapshot = snapshotSampleSourceRefArray(sampleSourceRefs, path12);
|
|
18225
|
+
const violations = [...snapshot.violations];
|
|
18226
|
+
const refs = [];
|
|
18227
|
+
for (let index = 0; index < snapshot.items.length; index += 1) {
|
|
18228
|
+
const defined = defineSafeResult(
|
|
18229
|
+
() => createSourceRef(snapshot.items[index]),
|
|
18230
|
+
"sourceRef",
|
|
18231
|
+
`${path12}.${index}`,
|
|
18232
|
+
"sampleSourceRefs.validation_error",
|
|
18233
|
+
"Sample source ref validation failed unexpectedly."
|
|
18234
|
+
);
|
|
18235
|
+
violations.push(...defined.violations);
|
|
18236
|
+
if (defined.value) refs[index] = defined.value;
|
|
18237
|
+
}
|
|
18238
|
+
return {
|
|
18239
|
+
value: violations.length === 0 ? Object.freeze(refs) : void 0,
|
|
18240
|
+
violations
|
|
18241
|
+
};
|
|
18242
|
+
}
|
|
18243
|
+
function snapshotSampleSourceRefArray(sampleSourceRefs, path12) {
|
|
18244
|
+
const lengthDescriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(
|
|
18245
|
+
sampleSourceRefs,
|
|
18246
|
+
"length",
|
|
18247
|
+
path12,
|
|
18248
|
+
"sampleSourceRefs.length.invalid",
|
|
18249
|
+
"sampleSourceRefs must expose a stable bounded array length."
|
|
18250
|
+
);
|
|
18251
|
+
if (lengthDescriptorSnapshot.violations.length > 0) {
|
|
18252
|
+
return { items: [], violations: lengthDescriptorSnapshot.violations };
|
|
18253
|
+
}
|
|
18254
|
+
const lengthDescriptor = lengthDescriptorSnapshot.descriptor;
|
|
18255
|
+
if (!lengthDescriptor || !("value" in lengthDescriptor)) {
|
|
18256
|
+
return {
|
|
18257
|
+
items: [],
|
|
18258
|
+
violations: [violation("sampleSourceRefs.length.invalid", path12, "sampleSourceRefs must expose a stable bounded array length.")]
|
|
18259
|
+
};
|
|
18260
|
+
}
|
|
18261
|
+
const lengthReadSnapshot = safeReadOwnDataPropertyForSourceSnapshot(
|
|
18262
|
+
sampleSourceRefs,
|
|
18263
|
+
"length",
|
|
18264
|
+
lengthDescriptor,
|
|
18265
|
+
path12,
|
|
18266
|
+
"sampleSourceRefs.length.invalid",
|
|
18267
|
+
"sampleSourceRefs must expose a stable bounded array length."
|
|
18268
|
+
);
|
|
18269
|
+
if (lengthReadSnapshot.violations.length > 0) {
|
|
18270
|
+
return { items: [], violations: lengthReadSnapshot.violations };
|
|
18271
|
+
}
|
|
18272
|
+
const length = lengthReadSnapshot.value;
|
|
18273
|
+
if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0 || length > MAX_SAMPLE_SOURCE_REFS) {
|
|
18274
|
+
return {
|
|
18275
|
+
items: [],
|
|
18276
|
+
violations: [violation("sampleSourceRefs.length.invalid", path12, "sampleSourceRefs must expose a stable bounded array length.")]
|
|
18277
|
+
};
|
|
18278
|
+
}
|
|
18279
|
+
const items = new Array(length);
|
|
18280
|
+
const violations = [];
|
|
18281
|
+
for (let index = 0; index < length; index += 1) {
|
|
18282
|
+
const itemPath = `${path12}.${index}`;
|
|
18283
|
+
const descriptorSnapshot = safeGetOwnPropertyDescriptorForSourceSnapshot(
|
|
18284
|
+
sampleSourceRefs,
|
|
18285
|
+
String(index),
|
|
18286
|
+
itemPath,
|
|
18287
|
+
"sampleSourceRefs.accessor_field",
|
|
18288
|
+
"sampleSourceRefs array entries must be data properties."
|
|
18289
|
+
);
|
|
18290
|
+
violations.push(...descriptorSnapshot.violations);
|
|
18291
|
+
const descriptor = descriptorSnapshot.descriptor;
|
|
18292
|
+
if (!descriptor) {
|
|
18293
|
+
violations.push(violation("sampleSourceRefs.missing_index", itemPath, "sampleSourceRefs must be a dense array."));
|
|
18294
|
+
continue;
|
|
18295
|
+
}
|
|
18296
|
+
if (!("value" in descriptor)) {
|
|
18297
|
+
violations.push(violation("sampleSourceRefs.accessor_field", itemPath, "sampleSourceRefs array entries must be data properties."));
|
|
18298
|
+
continue;
|
|
18299
|
+
}
|
|
18300
|
+
const readSnapshot = safeReadOwnDataPropertyForSourceSnapshot(
|
|
18301
|
+
sampleSourceRefs,
|
|
18302
|
+
String(index),
|
|
18303
|
+
descriptor,
|
|
18304
|
+
itemPath,
|
|
18305
|
+
"sampleSourceRefs.accessor_field",
|
|
18306
|
+
"sampleSourceRefs array entries must be data properties."
|
|
18307
|
+
);
|
|
18308
|
+
violations.push(...readSnapshot.violations);
|
|
18309
|
+
if (readSnapshot.violations.length > 0) continue;
|
|
18310
|
+
items[index] = readSnapshot.value;
|
|
18311
|
+
}
|
|
18312
|
+
return { items, violations };
|
|
18313
|
+
}
|
|
18314
|
+
function defineSafeResult(define, sourcePathPrefix, targetPathPrefix, fallbackCode, fallbackMessage) {
|
|
18315
|
+
try {
|
|
18316
|
+
return { value: define(), violations: [] };
|
|
18317
|
+
} catch (error) {
|
|
18318
|
+
if (error instanceof SourceContractValidationError) {
|
|
18319
|
+
return {
|
|
18320
|
+
violations: error.violations.map((violationItem) => ({
|
|
18321
|
+
...violationItem,
|
|
18322
|
+
path: remapPathPrefix(violationItem.path, sourcePathPrefix, targetPathPrefix)
|
|
18323
|
+
}))
|
|
18324
|
+
};
|
|
18325
|
+
}
|
|
18326
|
+
return { violations: [violation(fallbackCode, targetPathPrefix, fallbackMessage)] };
|
|
18327
|
+
}
|
|
18328
|
+
}
|
|
18329
|
+
function remapPathPrefix(path12, sourcePathPrefix, targetPathPrefix) {
|
|
18330
|
+
if (path12 === sourcePathPrefix) return targetPathPrefix;
|
|
18331
|
+
if (path12.startsWith(`${sourcePathPrefix}.`)) return `${targetPathPrefix}${path12.slice(sourcePathPrefix.length)}`;
|
|
18332
|
+
return path12;
|
|
18333
|
+
}
|
|
18334
|
+
|
|
17289
18335
|
// src/core/evidence-aligner.ts
|
|
17290
18336
|
import { createHash as createHash8 } from "crypto";
|
|
17291
18337
|
var DEFAULT_OPTIONS2 = {
|
|
@@ -20201,7 +21247,7 @@ import * as os7 from "os";
|
|
|
20201
21247
|
import * as readline from "readline";
|
|
20202
21248
|
import { createHash as createHash9, randomUUID as randomUUID26 } from "crypto";
|
|
20203
21249
|
var CODEX_VALIDATION_DEFAULT_MAX_CONTENT_CHARS = 1e4;
|
|
20204
|
-
function
|
|
21250
|
+
function isRecord7(value) {
|
|
20205
21251
|
return typeof value === "object" && value !== null;
|
|
20206
21252
|
}
|
|
20207
21253
|
function normalizeMaybeRealpath(p) {
|
|
@@ -20217,7 +21263,7 @@ function extractCodexContentText(content, maxContentChars = CODEX_VALIDATION_DEF
|
|
|
20217
21263
|
if (content.length > 0) texts.push(content);
|
|
20218
21264
|
} else if (Array.isArray(content)) {
|
|
20219
21265
|
for (const block of content) {
|
|
20220
|
-
if (!
|
|
21266
|
+
if (!isRecord7(block)) continue;
|
|
20221
21267
|
const b = block;
|
|
20222
21268
|
const t = typeof b.type === "string" ? b.type : "";
|
|
20223
21269
|
if (t !== "input_text" && t !== "output_text" && t !== "text") continue;
|
|
@@ -20297,7 +21343,7 @@ async function readCodexSessionMeta(filePath) {
|
|
|
20297
21343
|
try {
|
|
20298
21344
|
const obj = JSON.parse(line);
|
|
20299
21345
|
if (obj.type !== "session_meta") continue;
|
|
20300
|
-
if (!
|
|
21346
|
+
if (!isRecord7(obj.payload)) break;
|
|
20301
21347
|
const payload = obj.payload;
|
|
20302
21348
|
const sessionId = typeof payload.id === "string" ? payload.id : null;
|
|
20303
21349
|
const cwd = typeof payload.cwd === "string" ? payload.cwd : null;
|
|
@@ -20427,7 +21473,7 @@ async function normalizeCodexSessionFile(filePath, options = {}) {
|
|
|
20427
21473
|
continue;
|
|
20428
21474
|
}
|
|
20429
21475
|
if (entry.type === "session_meta") continue;
|
|
20430
|
-
if (entry.type !== "response_item" || !
|
|
21476
|
+
if (entry.type !== "response_item" || !isRecord7(entry.payload)) {
|
|
20431
21477
|
summary.skippedUnsupportedRecords += 1;
|
|
20432
21478
|
continue;
|
|
20433
21479
|
}
|
|
@@ -20577,7 +21623,7 @@ var CodexSessionHistoryImporter = class {
|
|
|
20577
21623
|
try {
|
|
20578
21624
|
const obj = JSON.parse(line);
|
|
20579
21625
|
if (obj.type !== "session_meta") continue;
|
|
20580
|
-
if (!
|
|
21626
|
+
if (!isRecord7(obj.payload)) break;
|
|
20581
21627
|
const payload = obj.payload;
|
|
20582
21628
|
const sessionId = typeof payload.id === "string" ? payload.id : null;
|
|
20583
21629
|
const cwd = typeof payload.cwd === "string" ? payload.cwd : null;
|
|
@@ -20785,7 +21831,7 @@ var CodexSessionHistoryImporter = class {
|
|
|
20785
21831
|
try {
|
|
20786
21832
|
const entry = JSON.parse(line);
|
|
20787
21833
|
result2.totalMessages++;
|
|
20788
|
-
if (entry.type === "response_item" &&
|
|
21834
|
+
if (entry.type === "response_item" && isRecord7(entry.payload)) {
|
|
20789
21835
|
const payload = entry.payload;
|
|
20790
21836
|
if (payload.type !== "message") continue;
|
|
20791
21837
|
const role = typeof payload.role === "string" ? payload.role : null;
|
|
@@ -21034,6 +22080,9 @@ export {
|
|
|
21034
22080
|
RetrievalResultTypeSchema,
|
|
21035
22081
|
Retriever,
|
|
21036
22082
|
RuleBasedPerspectiveObservationExtractor,
|
|
22083
|
+
SOURCE_CAPTURE_MODES,
|
|
22084
|
+
SOURCE_PRIVACY_CLASSES,
|
|
22085
|
+
SOURCE_TRANSFORMATION_KINDS,
|
|
21037
22086
|
SQLiteEventStore,
|
|
21038
22087
|
SearchIndexItemSchema,
|
|
21039
22088
|
SessionActorRepository,
|
|
@@ -21049,6 +22098,7 @@ export {
|
|
|
21049
22098
|
SharedStoreConfigSchema,
|
|
21050
22099
|
SharedTroubleshootingEntrySchema,
|
|
21051
22100
|
SharedVectorStore,
|
|
22101
|
+
SourceContractValidationError,
|
|
21052
22102
|
SummaryDeriver,
|
|
21053
22103
|
SyncWorker,
|
|
21054
22104
|
TaskActionProjector,
|
|
@@ -21079,6 +22129,7 @@ export {
|
|
|
21079
22129
|
VectorWorkerV2,
|
|
21080
22130
|
WorkingSetItemSchema,
|
|
21081
22131
|
actionIdForTaskEntity,
|
|
22132
|
+
assertSourceAdapterContract,
|
|
21082
22133
|
backfillPerspectiveSessionActors,
|
|
21083
22134
|
buildMemoryActorId,
|
|
21084
22135
|
createCodexSessionHistoryImporter,
|
|
@@ -21106,9 +22157,14 @@ export {
|
|
|
21106
22157
|
createSharedPromoter,
|
|
21107
22158
|
createSharedStore,
|
|
21108
22159
|
createSharedVectorStore,
|
|
22160
|
+
createSourceRef,
|
|
21109
22161
|
createSummaryDeriver,
|
|
21110
22162
|
createVectorWorker,
|
|
21111
22163
|
createVectorWorkerV2,
|
|
22164
|
+
defineSourceAdapter,
|
|
22165
|
+
defineSourceSchema,
|
|
22166
|
+
defineSourceTransformation,
|
|
22167
|
+
defineSourceTransformations,
|
|
21112
22168
|
deriveCodexSessionIdFromFileName,
|
|
21113
22169
|
detectContextContentType,
|
|
21114
22170
|
emptyRetentionAuditReport,
|
|
@@ -21132,8 +22188,13 @@ export {
|
|
|
21132
22188
|
isKnownBenignTransformersWarning,
|
|
21133
22189
|
isMissingTransformersDependencyError,
|
|
21134
22190
|
isSameCanonicalKey,
|
|
22191
|
+
isSourceCaptureMode,
|
|
22192
|
+
isSourcePrivacyClass,
|
|
22193
|
+
isSourceTransformationKind,
|
|
21135
22194
|
listCodexSessionFilesRecursive,
|
|
21136
22195
|
loadSessionRegistry,
|
|
22196
|
+
looksLikeLocalAbsolutePath,
|
|
22197
|
+
looksLikePrivacySensitiveSourceValue,
|
|
21137
22198
|
makeArtifactKey,
|
|
21138
22199
|
makeCanonicalKey,
|
|
21139
22200
|
makeDedupeKey,
|
|
@@ -21169,6 +22230,13 @@ export {
|
|
|
21169
22230
|
toDisclosureResultId,
|
|
21170
22231
|
toSQLiteTimestamp,
|
|
21171
22232
|
validateCodexSessions,
|
|
22233
|
+
validateSourceAdapterCapabilities,
|
|
22234
|
+
validateSourceAdapterContract,
|
|
22235
|
+
validateSourceAdapterIdentity,
|
|
22236
|
+
validateSourceRef,
|
|
22237
|
+
validateSourceSchema,
|
|
22238
|
+
validateSourceTransformationDeclaration,
|
|
22239
|
+
validateSourceTransformationDeclarations,
|
|
21172
22240
|
withSuppressedKnownTransformersWarnings,
|
|
21173
22241
|
writeGovernanceAuditEntry
|
|
21174
22242
|
};
|