@gmickel/gno 1.28.0 → 1.29.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/README.md +46 -20
- package/assets/skill/SKILL.md +33 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-b2zm0jjd.js +50 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +6 -6
- package/package.json +1 -1
- package/spec/cli.md +41 -1
- package/spec/db/schema.sql +19 -0
- package/spec/mcp.md +66 -0
- package/spec/output-schemas/ask.schema.json +31 -1
- package/spec/output-schemas/browser-clip-preview.schema.json +30 -0
- package/spec/output-schemas/collection-egress-check.schema.json +91 -0
- package/spec/output-schemas/collection-egress-policy-set.schema.json +56 -0
- package/spec/output-schemas/collection-egress-policy.schema.json +41 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +89 -2
- package/spec/output-schemas/context-capsule-verification.schema.json +1 -1
- package/spec/output-schemas/egress-audit-management.schema.json +88 -0
- package/spec/output-schemas/mcp-http-error.schema.json +113 -2
- package/spec/output-schemas/publish-artifact.schema.json +32 -0
- package/spec/output-schemas/record-import.schema.json +30 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +4 -0
- package/spec/output-schemas/search-results.schema.json +30 -0
- package/src/app/context-runtime-contract.ts +16 -7
- package/src/cli/commands/ask.ts +7 -0
- package/src/cli/commands/collection/index.ts +5 -0
- package/src/cli/commands/collection/policy.ts +126 -0
- package/src/cli/commands/context-build.ts +5 -0
- package/src/cli/commands/daemon.ts +45 -3
- package/src/cli/commands/egress-audit.ts +68 -0
- package/src/cli/commands/embed.ts +2 -0
- package/src/cli/commands/query.ts +12 -0
- package/src/cli/commands/replay.ts +13 -3
- package/src/cli/commands/vsearch.ts +3 -1
- package/src/cli/program.ts +123 -0
- package/src/config/index.ts +9 -0
- package/src/config/types.ts +50 -0
- package/src/core/browser-clip.ts +16 -1
- package/src/core/collection-egress-policy-projection.ts +28 -0
- package/src/core/collection-egress-policy-service.ts +443 -0
- package/src/core/collection-egress-policy-validation.ts +242 -0
- package/src/core/config-mutation.ts +31 -19
- package/src/core/context-capsule-schema.ts +111 -1
- package/src/core/context-capsule-validation.ts +4 -4
- package/src/core/context-capsule-verification.ts +5 -1
- package/src/core/context-capsule.ts +177 -132
- package/src/core/context-evidence.ts +86 -14
- package/src/core/destination-classifier.ts +402 -0
- package/src/core/egress-audit.ts +239 -0
- package/src/core/egress-authorization.ts +50 -0
- package/src/core/egress-enforcement.ts +264 -0
- package/src/core/egress-policy.ts +440 -0
- package/src/core/egress-provenance.ts +336 -0
- package/src/core/job-manager.ts +37 -0
- package/src/core/network-boundary-inventory.ts +261 -0
- package/src/core/retrieval-qrels.ts +6 -0
- package/src/core/retrieval-replay.ts +18 -4
- package/src/core/retrieval-trace-export.ts +23 -4
- package/src/core/retrieval-trace-management-helpers.ts +1 -0
- package/src/core/retrieval-trace-management-types.ts +3 -0
- package/src/core/retrieval-trace-management.ts +9 -1
- package/src/core/retrieval-trace-session.ts +94 -0
- package/src/core/retrieval-trace.ts +22 -0
- package/src/ingestion/record-adapter.ts +12 -1
- package/src/ingestion/record-container.ts +38 -22
- package/src/ingestion/sync.ts +15 -0
- package/src/ingestion/types.ts +2 -0
- package/src/llm/errors.ts +10 -0
- package/src/llm/http-inference.ts +175 -0
- package/src/llm/http-policy.ts +537 -0
- package/src/llm/httpEmbedding.ts +47 -28
- package/src/llm/httpGeneration.ts +31 -18
- package/src/llm/httpRerank.ts +30 -18
- package/src/llm/index.ts +1 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +55 -20
- package/src/llm/pinned-http-connection.ts +177 -0
- package/src/mcp/context.ts +53 -1
- package/src/mcp/http-egress.ts +220 -0
- package/src/mcp/http-security.ts +32 -21
- package/src/mcp/http-session.ts +13 -2
- package/src/mcp/http-transport.ts +96 -6
- package/src/mcp/sync-egress.ts +24 -0
- package/src/mcp/tools/add-collection.ts +4 -0
- package/src/mcp/tools/ask.ts +1 -1
- package/src/mcp/tools/context.ts +9 -2
- package/src/mcp/tools/egress.ts +247 -0
- package/src/mcp/tools/embed.ts +1 -0
- package/src/mcp/tools/index-cmd.ts +7 -0
- package/src/mcp/tools/index.ts +98 -0
- package/src/mcp/tools/query.ts +10 -0
- package/src/mcp/tools/remove-collection.ts +4 -0
- package/src/mcp/tools/sync.ts +6 -0
- package/src/mcp/tools/trace.ts +7 -1
- package/src/mcp/tools/vsearch.ts +1 -0
- package/src/pipeline/egress-lineage.ts +124 -0
- package/src/pipeline/hybrid.ts +14 -0
- package/src/pipeline/search.ts +12 -0
- package/src/pipeline/types.ts +3 -0
- package/src/pipeline/vsearch.ts +41 -20
- package/src/publish/artifact.ts +31 -3
- package/src/publish/export-service.ts +25 -0
- package/src/sdk/client.ts +119 -2
- package/src/sdk/embed.ts +1 -0
- package/src/sdk/types.ts +33 -0
- package/src/serve/clipper-capture.ts +5 -1
- package/src/serve/closed-json.ts +61 -0
- package/src/serve/config-sync.ts +4 -1
- package/src/serve/context.ts +1 -0
- package/src/serve/doc-events.ts +110 -39
- package/src/serve/public/components/CollectionEgressCheckPanel.tsx +411 -0
- package/src/serve/public/components/CollectionEgressPolicyEditor.tsx +78 -0
- package/src/serve/public/components/CollectionModelDialog.tsx +93 -9
- package/src/serve/public/components/EgressAuditPanel.tsx +278 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Collections.tsx +3 -0
- package/src/serve/resident-request.ts +80 -3
- package/src/serve/resident-runtime.ts +63 -1
- package/src/serve/routes/api.ts +174 -0
- package/src/serve/routes/clipper.ts +64 -1
- package/src/serve/routes/mcp.ts +6 -0
- package/src/serve/routes/traces.ts +27 -4
- package/src/serve/server.ts +118 -7
- package/src/store/migrations/023-collection-egress-policy.ts +61 -0
- package/src/store/migrations/024-egress-derived-lineage.ts +121 -0
- package/src/store/migrations/025-collection-egress-policy-revision.ts +40 -0
- package/src/store/migrations/index.ts +6 -0
- package/src/store/retrieval-trace-codec.ts +15 -0
- package/src/store/sqlite/adapter.ts +170 -7
- package/src/store/sqlite/change-journal-store.ts +41 -2
- package/src/store/sqlite/egress-audit-store.ts +485 -0
- package/src/store/sqlite/retrieval-trace-management-store.ts +47 -6
- package/src/store/sqlite/retrieval-trace-retention.ts +2 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +8 -1
- package/src/store/sqlite/retrieval-trace-store.ts +104 -5
- package/src/store/types.ts +126 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.28.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.28.0.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-vn5f663b.js +0 -50
|
@@ -15,7 +15,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
15
15
|
// node:path basename: no Bun path utilities.
|
|
16
16
|
import { basename } from "node:path";
|
|
17
17
|
|
|
18
|
-
import type {
|
|
18
|
+
import type { EgressLineage } from "../../core/egress-provenance";
|
|
19
19
|
import type {
|
|
20
20
|
ActivationIndexDocument,
|
|
21
21
|
ActivationIndexIdentity,
|
|
@@ -44,6 +44,15 @@ import type {
|
|
|
44
44
|
DocumentInput,
|
|
45
45
|
DocumentRow,
|
|
46
46
|
EmbeddingCleanupStats,
|
|
47
|
+
EgressAuditCursor,
|
|
48
|
+
EgressAuditDeleteResult,
|
|
49
|
+
EgressAuditPage,
|
|
50
|
+
EgressAuditPurgeResult,
|
|
51
|
+
EgressAuditReceiptInput,
|
|
52
|
+
EgressAuditReceiptRow,
|
|
53
|
+
EgressAuditRetentionPolicy,
|
|
54
|
+
EgressAuditRetentionResult,
|
|
55
|
+
EgressAuditStatusResult,
|
|
47
56
|
FtsResult,
|
|
48
57
|
FtsSearchOptions,
|
|
49
58
|
GetGraphOptions,
|
|
@@ -93,6 +102,14 @@ import type {
|
|
|
93
102
|
import type { SqliteDbProvider } from "./types";
|
|
94
103
|
|
|
95
104
|
import { buildUri, deriveDocid, stripUriIndex } from "../../app/constants";
|
|
105
|
+
import {
|
|
106
|
+
type Collection,
|
|
107
|
+
type Context,
|
|
108
|
+
type EgressPolicy,
|
|
109
|
+
type EgressPolicySource,
|
|
110
|
+
type FtsTokenizer,
|
|
111
|
+
resolveConfiguredEgressPolicy,
|
|
112
|
+
} from "../../config/types";
|
|
96
113
|
import { analyzeGraphCommunities } from "../../core/graph-analysis";
|
|
97
114
|
import {
|
|
98
115
|
buildWikiBestMatchSubquery,
|
|
@@ -127,6 +144,16 @@ import {
|
|
|
127
144
|
purgeDocumentChanges as purgeStoredDocumentChanges,
|
|
128
145
|
snapshotDocumentChange,
|
|
129
146
|
} from "./change-journal-store";
|
|
147
|
+
import {
|
|
148
|
+
appendEgressAuditReceipt as appendStoredEgressAuditReceipt,
|
|
149
|
+
appendEgressAuditReceiptWithRetention as appendStoredEgressAuditReceiptWithRetention,
|
|
150
|
+
deleteEgressAuditReceipt as deleteStoredEgressAuditReceipt,
|
|
151
|
+
enforceEgressAuditRetention as enforceStoredEgressAuditRetention,
|
|
152
|
+
getEgressAuditReceipt as getStoredEgressAuditReceipt,
|
|
153
|
+
getEgressAuditStatus as getStoredEgressAuditStatus,
|
|
154
|
+
listEgressAuditReceipts as listStoredEgressAuditReceipts,
|
|
155
|
+
purgeEgressAuditReceipts as purgeStoredEgressAuditReceipts,
|
|
156
|
+
} from "./egress-audit-store";
|
|
130
157
|
import { loadFts5Snowball } from "./fts5-snowball";
|
|
131
158
|
import {
|
|
132
159
|
appendExportManifest as appendStoredTraceExportManifest,
|
|
@@ -149,6 +176,7 @@ import {
|
|
|
149
176
|
finalizeTrace as finalizeStoredTrace,
|
|
150
177
|
getTrace as getStoredTrace,
|
|
151
178
|
listTraces as listStoredTraces,
|
|
179
|
+
mergeTraceEgressLineage as mergeStoredTraceEgressLineage,
|
|
152
180
|
} from "./retrieval-trace-store";
|
|
153
181
|
|
|
154
182
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -589,8 +617,12 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
589
617
|
|
|
590
618
|
// Upsert collections
|
|
591
619
|
const stmt = db.prepare(`
|
|
592
|
-
INSERT INTO collections (
|
|
593
|
-
|
|
620
|
+
INSERT INTO collections (
|
|
621
|
+
name, path, pattern, include, exclude, update_cmd, language_hint,
|
|
622
|
+
egress_policy, egress_policy_source, egress_policy_revision,
|
|
623
|
+
synced_at
|
|
624
|
+
)
|
|
625
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
594
626
|
ON CONFLICT(name) DO UPDATE SET
|
|
595
627
|
path = excluded.path,
|
|
596
628
|
pattern = excluded.pattern,
|
|
@@ -598,10 +630,29 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
598
630
|
exclude = excluded.exclude,
|
|
599
631
|
update_cmd = excluded.update_cmd,
|
|
600
632
|
language_hint = excluded.language_hint,
|
|
633
|
+
egress_policy = CASE
|
|
634
|
+
WHEN excluded.egress_policy_source = 'config_default'
|
|
635
|
+
AND collections.egress_policy_source = 'legacy_default'
|
|
636
|
+
THEN collections.egress_policy
|
|
637
|
+
ELSE excluded.egress_policy
|
|
638
|
+
END,
|
|
639
|
+
egress_policy_source = CASE
|
|
640
|
+
WHEN excluded.egress_policy_source = 'config_default'
|
|
641
|
+
AND collections.egress_policy_source = 'legacy_default'
|
|
642
|
+
THEN collections.egress_policy_source
|
|
643
|
+
ELSE excluded.egress_policy_source
|
|
644
|
+
END,
|
|
645
|
+
egress_policy_revision = CASE
|
|
646
|
+
WHEN excluded.egress_policy_source = 'config_default'
|
|
647
|
+
AND collections.egress_policy_source = 'legacy_default'
|
|
648
|
+
THEN collections.egress_policy_revision
|
|
649
|
+
ELSE excluded.egress_policy_revision
|
|
650
|
+
END,
|
|
601
651
|
synced_at = datetime('now')
|
|
602
652
|
`);
|
|
603
653
|
|
|
604
654
|
for (const c of collections) {
|
|
655
|
+
const egress = resolveConfiguredEgressPolicy(c);
|
|
605
656
|
stmt.run(
|
|
606
657
|
c.name,
|
|
607
658
|
c.path,
|
|
@@ -609,7 +660,10 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
609
660
|
c.include.length > 0 ? JSON.stringify(c.include) : null,
|
|
610
661
|
c.exclude.length > 0 ? JSON.stringify(c.exclude) : null,
|
|
611
662
|
c.updateCmd ?? null,
|
|
612
|
-
c.languageHint ?? null
|
|
663
|
+
c.languageHint ?? null,
|
|
664
|
+
egress.policy,
|
|
665
|
+
egress.source,
|
|
666
|
+
c.egressPolicyRevision ?? 0
|
|
613
667
|
);
|
|
614
668
|
}
|
|
615
669
|
});
|
|
@@ -631,8 +685,12 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
631
685
|
try {
|
|
632
686
|
const db = this.ensureOpen();
|
|
633
687
|
const stmt = db.prepare(`
|
|
634
|
-
INSERT INTO collections (
|
|
635
|
-
|
|
688
|
+
INSERT INTO collections (
|
|
689
|
+
name, path, pattern, include, exclude, update_cmd, language_hint,
|
|
690
|
+
egress_policy, egress_policy_source, egress_policy_revision,
|
|
691
|
+
synced_at
|
|
692
|
+
)
|
|
693
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
636
694
|
ON CONFLICT(name) DO UPDATE SET
|
|
637
695
|
path = excluded.path,
|
|
638
696
|
pattern = excluded.pattern,
|
|
@@ -640,6 +698,24 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
640
698
|
exclude = excluded.exclude,
|
|
641
699
|
update_cmd = excluded.update_cmd,
|
|
642
700
|
language_hint = excluded.language_hint,
|
|
701
|
+
egress_policy = CASE
|
|
702
|
+
WHEN excluded.egress_policy_source = 'config_default'
|
|
703
|
+
AND collections.egress_policy_source = 'legacy_default'
|
|
704
|
+
THEN collections.egress_policy
|
|
705
|
+
ELSE excluded.egress_policy
|
|
706
|
+
END,
|
|
707
|
+
egress_policy_source = CASE
|
|
708
|
+
WHEN excluded.egress_policy_source = 'config_default'
|
|
709
|
+
AND collections.egress_policy_source = 'legacy_default'
|
|
710
|
+
THEN collections.egress_policy_source
|
|
711
|
+
ELSE excluded.egress_policy_source
|
|
712
|
+
END,
|
|
713
|
+
egress_policy_revision = CASE
|
|
714
|
+
WHEN excluded.egress_policy_source = 'config_default'
|
|
715
|
+
AND collections.egress_policy_source = 'legacy_default'
|
|
716
|
+
THEN collections.egress_policy_revision
|
|
717
|
+
ELSE excluded.egress_policy_revision
|
|
718
|
+
END,
|
|
643
719
|
synced_at = datetime('now')
|
|
644
720
|
WHERE collections.path IS NOT excluded.path
|
|
645
721
|
OR collections.pattern IS NOT excluded.pattern
|
|
@@ -647,9 +723,21 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
647
723
|
OR collections.exclude IS NOT excluded.exclude
|
|
648
724
|
OR collections.update_cmd IS NOT excluded.update_cmd
|
|
649
725
|
OR collections.language_hint IS NOT excluded.language_hint
|
|
726
|
+
OR (
|
|
727
|
+
NOT (
|
|
728
|
+
excluded.egress_policy_source = 'config_default'
|
|
729
|
+
AND collections.egress_policy_source = 'legacy_default'
|
|
730
|
+
)
|
|
731
|
+
AND (
|
|
732
|
+
collections.egress_policy IS NOT excluded.egress_policy
|
|
733
|
+
OR collections.egress_policy_source IS NOT excluded.egress_policy_source
|
|
734
|
+
OR collections.egress_policy_revision IS NOT excluded.egress_policy_revision
|
|
735
|
+
)
|
|
736
|
+
)
|
|
650
737
|
`);
|
|
651
738
|
const transaction = db.transaction(() => {
|
|
652
739
|
for (const collection of collections) {
|
|
740
|
+
const egress = resolveConfiguredEgressPolicy(collection);
|
|
653
741
|
stmt.run(
|
|
654
742
|
collection.name,
|
|
655
743
|
collection.path,
|
|
@@ -661,7 +749,10 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
661
749
|
? JSON.stringify(collection.exclude)
|
|
662
750
|
: null,
|
|
663
751
|
collection.updateCmd ?? null,
|
|
664
|
-
collection.languageHint ?? null
|
|
752
|
+
collection.languageHint ?? null,
|
|
753
|
+
egress.policy,
|
|
754
|
+
egress.source,
|
|
755
|
+
collection.egressPolicyRevision ?? 0
|
|
665
756
|
);
|
|
666
757
|
}
|
|
667
758
|
});
|
|
@@ -943,6 +1034,13 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
943
1034
|
return createStoredTrace(this.ensureOpen(), input);
|
|
944
1035
|
}
|
|
945
1036
|
|
|
1037
|
+
async mergeRetrievalTraceEgressLineage(
|
|
1038
|
+
traceId: string,
|
|
1039
|
+
lineage: EgressLineage
|
|
1040
|
+
): Promise<StoreResult<RetrievalTraceAppendResult>> {
|
|
1041
|
+
return mergeStoredTraceEgressLineage(this.ensureOpen(), traceId, lineage);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
946
1044
|
async getRetrievalTrace(
|
|
947
1045
|
traceId: string
|
|
948
1046
|
): Promise<StoreResult<RetrievalTraceBundle | null>> {
|
|
@@ -1038,6 +1136,61 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
1038
1136
|
return enforceStoredTraceRetention(this.ensureOpen(), policy, nowMs);
|
|
1039
1137
|
}
|
|
1040
1138
|
|
|
1139
|
+
async appendEgressAuditReceipt(
|
|
1140
|
+
receipt: EgressAuditReceiptInput
|
|
1141
|
+
): Promise<StoreResult<RetrievalTraceAppendResult>> {
|
|
1142
|
+
return appendStoredEgressAuditReceipt(this.ensureOpen(), receipt);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
async appendEgressAuditReceiptWithRetention(
|
|
1146
|
+
receipt: EgressAuditReceiptInput,
|
|
1147
|
+
policy: EgressAuditRetentionPolicy,
|
|
1148
|
+
nowMs: number
|
|
1149
|
+
): Promise<StoreResult<RetrievalTraceAppendResult>> {
|
|
1150
|
+
return appendStoredEgressAuditReceiptWithRetention(
|
|
1151
|
+
this.ensureOpen(),
|
|
1152
|
+
receipt,
|
|
1153
|
+
policy,
|
|
1154
|
+
nowMs
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
async listEgressAuditReceipts(
|
|
1159
|
+
limit: number,
|
|
1160
|
+
cursor?: EgressAuditCursor
|
|
1161
|
+
): Promise<StoreResult<EgressAuditPage>> {
|
|
1162
|
+
return listStoredEgressAuditReceipts(this.ensureOpen(), limit, cursor);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
async getEgressAuditReceipt(
|
|
1166
|
+
auditId: string
|
|
1167
|
+
): Promise<StoreResult<EgressAuditReceiptRow | null>> {
|
|
1168
|
+
return getStoredEgressAuditReceipt(this.ensureOpen(), auditId);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
async deleteEgressAuditReceipt(
|
|
1172
|
+
auditId: string
|
|
1173
|
+
): Promise<StoreResult<EgressAuditDeleteResult>> {
|
|
1174
|
+
return deleteStoredEgressAuditReceipt(this.ensureOpen(), auditId);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
async getEgressAuditStatus(): Promise<StoreResult<EgressAuditStatusResult>> {
|
|
1178
|
+
return getStoredEgressAuditStatus(this.ensureOpen());
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
async enforceEgressAuditRetention(
|
|
1182
|
+
policy: EgressAuditRetentionPolicy,
|
|
1183
|
+
nowMs: number
|
|
1184
|
+
): Promise<StoreResult<EgressAuditRetentionResult>> {
|
|
1185
|
+
return enforceStoredEgressAuditRetention(this.ensureOpen(), policy, nowMs);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
async purgeEgressAuditReceipts(): Promise<
|
|
1189
|
+
StoreResult<EgressAuditPurgeResult>
|
|
1190
|
+
> {
|
|
1191
|
+
return purgeStoredEgressAuditReceipts(this.ensureOpen());
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1041
1194
|
getContextGeneration(): number {
|
|
1042
1195
|
return this.contextGeneration;
|
|
1043
1196
|
}
|
|
@@ -4709,6 +4862,8 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
4709
4862
|
interface CollectionStat {
|
|
4710
4863
|
name: string;
|
|
4711
4864
|
path: string;
|
|
4865
|
+
egress_policy: EgressPolicy;
|
|
4866
|
+
egress_policy_source: EgressPolicySource;
|
|
4712
4867
|
total: number;
|
|
4713
4868
|
active: number;
|
|
4714
4869
|
errored: number;
|
|
@@ -4760,6 +4915,8 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
4760
4915
|
SELECT
|
|
4761
4916
|
c.name,
|
|
4762
4917
|
c.path,
|
|
4918
|
+
c.egress_policy,
|
|
4919
|
+
c.egress_policy_source,
|
|
4763
4920
|
COALESCE(ds.total, 0) AS total,
|
|
4764
4921
|
COALESCE(ds.active, 0) AS active,
|
|
4765
4922
|
COALESCE(ds.errored, 0) AS errored,
|
|
@@ -4856,6 +5013,8 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
4856
5013
|
collections: collectionStats.map((s) => ({
|
|
4857
5014
|
name: s.name,
|
|
4858
5015
|
path: s.path,
|
|
5016
|
+
egressPolicy: s.egress_policy,
|
|
5017
|
+
egressPolicySource: s.egress_policy_source,
|
|
4859
5018
|
totalDocuments: s.total,
|
|
4860
5019
|
activeDocuments: s.active,
|
|
4861
5020
|
errorDocuments: s.errored,
|
|
@@ -5132,6 +5291,8 @@ interface DbCollectionRow {
|
|
|
5132
5291
|
exclude: string | null;
|
|
5133
5292
|
update_cmd: string | null;
|
|
5134
5293
|
language_hint: string | null;
|
|
5294
|
+
egress_policy: EgressPolicy;
|
|
5295
|
+
egress_policy_source: EgressPolicySource;
|
|
5135
5296
|
synced_at: string;
|
|
5136
5297
|
}
|
|
5137
5298
|
|
|
@@ -5230,6 +5391,8 @@ function mapCollectionRow(row: DbCollectionRow): CollectionRow {
|
|
|
5230
5391
|
exclude: row.exclude ? JSON.parse(row.exclude) : null,
|
|
5231
5392
|
updateCmd: row.update_cmd,
|
|
5232
5393
|
languageHint: row.language_hint,
|
|
5394
|
+
egressPolicy: row.egress_policy,
|
|
5395
|
+
egressPolicySource: row.egress_policy_source,
|
|
5233
5396
|
syncedAt: row.synced_at,
|
|
5234
5397
|
};
|
|
5235
5398
|
}
|
|
@@ -22,6 +22,10 @@ import {
|
|
|
22
22
|
serializeDocumentChangeStructureDelta,
|
|
23
23
|
validateDocumentChangeRetentionPolicy,
|
|
24
24
|
} from "../../core/change-journal";
|
|
25
|
+
import {
|
|
26
|
+
createEgressLineage,
|
|
27
|
+
egressLineageSchema,
|
|
28
|
+
} from "../../core/egress-provenance";
|
|
25
29
|
import { err, ok } from "../types";
|
|
26
30
|
|
|
27
31
|
const DAY_MS = 86_400_000;
|
|
@@ -74,6 +78,8 @@ interface DbDocumentChangeRow {
|
|
|
74
78
|
structure_truncated: number;
|
|
75
79
|
observed_at_ms: number;
|
|
76
80
|
byte_size: number;
|
|
81
|
+
egress_lineage_json: string;
|
|
82
|
+
egress_lineage_bytes: number;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
const utf8ByteLength = (value: string | null): number =>
|
|
@@ -127,6 +133,7 @@ const mapRow = (row: DbDocumentChangeRow): DocumentChangeRow => ({
|
|
|
127
133
|
dates: JSON.parse(row.date_delta_json),
|
|
128
134
|
truncated: row.structure_truncated === 1,
|
|
129
135
|
},
|
|
136
|
+
egressLineage: egressLineageSchema.parse(JSON.parse(row.egress_lineage_json)),
|
|
130
137
|
observedAtMs: row.observed_at_ms,
|
|
131
138
|
byteSize: row.byte_size,
|
|
132
139
|
});
|
|
@@ -249,11 +256,38 @@ export const appendDocumentChange = (
|
|
|
249
256
|
} = serializeDocumentChangeStructureDelta(draft.structureDelta);
|
|
250
257
|
const old = draft.oldSnapshot;
|
|
251
258
|
const next = draft.newSnapshot;
|
|
259
|
+
const collectionPolicy = db
|
|
260
|
+
.query<
|
|
261
|
+
{
|
|
262
|
+
egress_policy: "local_only" | "lan" | "remote";
|
|
263
|
+
egress_policy_source: "explicit" | "config_default" | "legacy_default";
|
|
264
|
+
},
|
|
265
|
+
[string]
|
|
266
|
+
>(
|
|
267
|
+
`SELECT egress_policy, egress_policy_source
|
|
268
|
+
FROM collections WHERE name = ?`
|
|
269
|
+
)
|
|
270
|
+
.get(draft.collection);
|
|
271
|
+
if (!collectionPolicy) {
|
|
272
|
+
throw new Error(
|
|
273
|
+
`Document change policy lineage references unknown collection ${draft.collection}`
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
const egressLineage = createEgressLineage([
|
|
277
|
+
{
|
|
278
|
+
collection: draft.collection,
|
|
279
|
+
policy: collectionPolicy.egress_policy,
|
|
280
|
+
source: collectionPolicy.egress_policy_source,
|
|
281
|
+
},
|
|
282
|
+
]);
|
|
283
|
+
const egressLineageJson = JSON.stringify(egressLineage);
|
|
284
|
+
const egressLineageBytes = UTF8_ENCODER.encode(egressLineageJson).byteLength;
|
|
252
285
|
const storedByteSize = byteSize(draft, [
|
|
253
286
|
headingDeltaJson,
|
|
254
287
|
linkDeltaJson,
|
|
255
288
|
typedEdgeDeltaJson,
|
|
256
289
|
dateDeltaJson,
|
|
290
|
+
egressLineageJson,
|
|
257
291
|
]);
|
|
258
292
|
const inserted = db.run(
|
|
259
293
|
`INSERT INTO document_changes (
|
|
@@ -262,8 +296,9 @@ export const appendDocumentChange = (
|
|
|
262
296
|
old_source_hash, new_source_hash, old_mirror_hash, new_mirror_hash,
|
|
263
297
|
old_active, new_active, heading_delta_json, link_delta_json,
|
|
264
298
|
typed_edge_delta_json, date_delta_json, structure_truncated,
|
|
265
|
-
|
|
266
|
-
|
|
299
|
+
effective_egress_policy, egress_lineage_digest, egress_lineage_json,
|
|
300
|
+
egress_lineage_bytes, observed_at_ms, byte_size
|
|
301
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
267
302
|
[
|
|
268
303
|
draft.documentId,
|
|
269
304
|
draft.collection,
|
|
@@ -285,6 +320,10 @@ export const appendDocumentChange = (
|
|
|
285
320
|
typedEdgeDeltaJson,
|
|
286
321
|
dateDeltaJson,
|
|
287
322
|
delta.truncated ? 1 : 0,
|
|
323
|
+
egressLineage.effectivePolicy,
|
|
324
|
+
egressLineage.digest,
|
|
325
|
+
egressLineageJson,
|
|
326
|
+
egressLineageBytes,
|
|
288
327
|
draft.observedAtMs,
|
|
289
328
|
storedByteSize,
|
|
290
329
|
]
|