@izagood/avcs 0.1.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/LICENSE +201 -0
- package/README.md +221 -0
- package/dist/api/repo.d.ts +616 -0
- package/dist/api/repo.d.ts.map +1 -0
- package/dist/api/repo.js +1772 -0
- package/dist/api/repo.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +660 -0
- package/dist/cli.js.map +1 -0
- package/dist/concurrency/lease.d.ts +27 -0
- package/dist/concurrency/lease.d.ts.map +1 -0
- package/dist/concurrency/lease.js +63 -0
- package/dist/concurrency/lease.js.map +1 -0
- package/dist/core/canonical.d.ts +16 -0
- package/dist/core/canonical.d.ts.map +1 -0
- package/dist/core/canonical.js +66 -0
- package/dist/core/canonical.js.map +1 -0
- package/dist/core/cbor.d.ts +9 -0
- package/dist/core/cbor.d.ts.map +1 -0
- package/dist/core/cbor.js +213 -0
- package/dist/core/cbor.js.map +1 -0
- package/dist/core/clock.d.ts +18 -0
- package/dist/core/clock.d.ts.map +1 -0
- package/dist/core/clock.js +32 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/identity.d.ts +34 -0
- package/dist/core/identity.d.ts.map +1 -0
- package/dist/core/identity.js +62 -0
- package/dist/core/identity.js.map +1 -0
- package/dist/hub/hubClient.d.ts +38 -0
- package/dist/hub/hubClient.d.ts.map +1 -0
- package/dist/hub/hubClient.js +157 -0
- package/dist/hub/hubClient.js.map +1 -0
- package/dist/hub/hubServer.d.ts +28 -0
- package/dist/hub/hubServer.d.ts.map +1 -0
- package/dist/hub/hubServer.js +365 -0
- package/dist/hub/hubServer.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/objects/types.d.ts +352 -0
- package/dist/objects/types.d.ts.map +1 -0
- package/dist/objects/types.js +17 -0
- package/dist/objects/types.js.map +1 -0
- package/dist/observe/logger.d.ts +27 -0
- package/dist/observe/logger.d.ts.map +1 -0
- package/dist/observe/logger.js +37 -0
- package/dist/observe/logger.js.map +1 -0
- package/dist/observe/metrics.d.ts +20 -0
- package/dist/observe/metrics.d.ts.map +1 -0
- package/dist/observe/metrics.js +42 -0
- package/dist/observe/metrics.js.map +1 -0
- package/dist/policy/owners.d.ts +5 -0
- package/dist/policy/owners.d.ts.map +1 -0
- package/dist/policy/owners.js +38 -0
- package/dist/policy/owners.js.map +1 -0
- package/dist/policy/reliability.d.ts +7 -0
- package/dist/policy/reliability.d.ts.map +1 -0
- package/dist/policy/reliability.js +41 -0
- package/dist/policy/reliability.js.map +1 -0
- package/dist/query/diff.d.ts +16 -0
- package/dist/query/diff.d.ts.map +1 -0
- package/dist/query/diff.js +32 -0
- package/dist/query/diff.js.map +1 -0
- package/dist/reducer/incremental.d.ts +2 -0
- package/dist/reducer/incremental.d.ts.map +1 -0
- package/dist/reducer/incremental.js +14 -0
- package/dist/reducer/incremental.js.map +1 -0
- package/dist/reducer/policy.d.ts +17 -0
- package/dist/reducer/policy.d.ts.map +1 -0
- package/dist/reducer/policy.js +143 -0
- package/dist/reducer/policy.js.map +1 -0
- package/dist/reducer/reducer.d.ts +155 -0
- package/dist/reducer/reducer.d.ts.map +1 -0
- package/dist/reducer/reducer.js +849 -0
- package/dist/reducer/reducer.js.map +1 -0
- package/dist/release/sbom.d.ts +7 -0
- package/dist/release/sbom.d.ts.map +1 -0
- package/dist/release/sbom.js +26 -0
- package/dist/release/sbom.js.map +1 -0
- package/dist/semantic/contract.d.ts +32 -0
- package/dist/semantic/contract.d.ts.map +1 -0
- package/dist/semantic/contract.js +150 -0
- package/dist/semantic/contract.js.map +1 -0
- package/dist/semantic/symbols.d.ts +45 -0
- package/dist/semantic/symbols.d.ts.map +1 -0
- package/dist/semantic/symbols.js +323 -0
- package/dist/semantic/symbols.js.map +1 -0
- package/dist/store/applyRedactions.d.ts +16 -0
- package/dist/store/applyRedactions.d.ts.map +1 -0
- package/dist/store/applyRedactions.js +60 -0
- package/dist/store/applyRedactions.js.map +1 -0
- package/dist/store/lock.d.ts +12 -0
- package/dist/store/lock.d.ts.map +1 -0
- package/dist/store/lock.js +63 -0
- package/dist/store/lock.js.map +1 -0
- package/dist/store/objectStore.d.ts +127 -0
- package/dist/store/objectStore.d.ts.map +1 -0
- package/dist/store/objectStore.js +549 -0
- package/dist/store/objectStore.js.map +1 -0
- package/dist/validation/repair.d.ts +31 -0
- package/dist/validation/repair.d.ts.map +1 -0
- package/dist/validation/repair.js +37 -0
- package/dist/validation/repair.js.map +1 -0
- package/dist/validation/runner.d.ts +20 -0
- package/dist/validation/runner.d.ts.map +1 -0
- package/dist/validation/runner.js +90 -0
- package/dist/validation/runner.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Phase 3: cryptographic identity.
|
|
2
|
+
//
|
|
3
|
+
// Until now "this evidence came from ci_bot" and "a human made this decision" were
|
|
4
|
+
// self-reported strings an agent could forge. Identity makes them checkable: an
|
|
5
|
+
// actor holds an ed25519 keypair, signs the content-address (oid) of objects it
|
|
6
|
+
// produces, and the reducer's trust gate only honors evidence/decisions whose
|
|
7
|
+
// signature verifies against a registered public key for the claimed actor.
|
|
8
|
+
//
|
|
9
|
+
// ed25519 via node:crypto — no external dependency.
|
|
10
|
+
import { generateKeyPairSync, sign as nodeSign, verify as nodeVerify } from "node:crypto";
|
|
11
|
+
import { Buffer } from "node:buffer";
|
|
12
|
+
export function generateKeypair() {
|
|
13
|
+
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
|
|
14
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
15
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
16
|
+
});
|
|
17
|
+
return { publicKey: publicKey, privateKey: privateKey };
|
|
18
|
+
}
|
|
19
|
+
export function signMessage(privateKeyPem, message) {
|
|
20
|
+
// ed25519 is a one-shot signature: algorithm arg is null.
|
|
21
|
+
return nodeSign(null, Buffer.from(message, "utf8"), privateKeyPem).toString("base64");
|
|
22
|
+
}
|
|
23
|
+
export function verifyMessage(publicKeyPem, message, sigB64) {
|
|
24
|
+
try {
|
|
25
|
+
return nodeVerify(null, Buffer.from(message, "utf8"), publicKeyPem, Buffer.from(sigB64, "base64"));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** A registry of trusted public keys, keyed by keyId. */
|
|
32
|
+
export class Keyring {
|
|
33
|
+
#keys = new Map();
|
|
34
|
+
register(rec) {
|
|
35
|
+
this.#keys.set(rec.keyId, rec);
|
|
36
|
+
}
|
|
37
|
+
get(keyId) {
|
|
38
|
+
return this.#keys.get(keyId);
|
|
39
|
+
}
|
|
40
|
+
has(keyId) {
|
|
41
|
+
return this.#keys.has(keyId);
|
|
42
|
+
}
|
|
43
|
+
get size() {
|
|
44
|
+
return this.#keys.size;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Verify a signature over `oid`, claimed to come from `claimedActorId`.
|
|
48
|
+
* Returns true only if the signing key is registered AND its registered actor
|
|
49
|
+
* matches the claim — i.e. you cannot sign as ci_bot with ai_agent's key.
|
|
50
|
+
*/
|
|
51
|
+
verifyFor(claimedActorId, oid, sig) {
|
|
52
|
+
if (!sig)
|
|
53
|
+
return false;
|
|
54
|
+
const rec = this.#keys.get(sig.keyId);
|
|
55
|
+
if (!rec)
|
|
56
|
+
return false;
|
|
57
|
+
if (rec.actorId !== claimedActorId)
|
|
58
|
+
return false;
|
|
59
|
+
return verifyMessage(rec.publicKey, oid, sig.sig);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/core/identity.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,EAAE;AACF,mFAAmF;AACnF,gFAAgF;AAChF,gFAAgF;AAChF,8EAA8E;AAC9E,4EAA4E;AAC5E,EAAE;AACF,oDAAoD;AAEpD,OAAO,EAAE,mBAAmB,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAcrC,MAAM,UAAU,eAAe;IAC7B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,mBAAmB,CAAC,SAAS,EAAE;QAC/D,iBAAiB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE;QAClD,kBAAkB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;KACrD,CAAC,CAAC;IACH,OAAO,EAAE,SAAS,EAAE,SAAmB,EAAE,UAAU,EAAE,UAAoB,EAAE,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,aAAqB,EAAE,OAAe;IAChE,0DAA0D;IAC1D,OAAO,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,YAAoB,EAAE,OAAe,EAAE,MAAc;IACjF,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AASD,yDAAyD;AACzD,MAAM,OAAO,OAAO;IAClB,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAErC,QAAQ,CAAC,GAAc;QACrB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC;IACD,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,cAAsB,EAAE,GAAW,EAAE,GAA0B;QACvE,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,IAAI,GAAG,CAAC,OAAO,KAAK,cAAc;YAAE,OAAO,KAAK,CAAC;QACjD,OAAO,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IACpD,CAAC;CACF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push objects the hub lacks: diff our local oids against GET /have and POST the
|
|
3
|
+
* missing ones. Private (stash) ops are local-only and never gossiped — same rule as
|
|
4
|
+
* Repo.pull. Returns how many objects were pushed.
|
|
5
|
+
*/
|
|
6
|
+
export declare function pushToHub(localRepoDir: string, hubUrl: string): Promise<{
|
|
7
|
+
pushed: number;
|
|
8
|
+
rejected: number;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Pull objects the local store lacks: GET /have, then GET each missing /objects/:oid
|
|
12
|
+
* and put it locally (idempotent, content-addressed). Returns how many were pulled.
|
|
13
|
+
*/
|
|
14
|
+
export declare function pullFromHub(localRepoDir: string, hubUrl: string): Promise<{
|
|
15
|
+
pulled: number;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Request a finalize (= PR merge) on the hub (E6): POST /finalize with the view, the new
|
|
19
|
+
* checkpoint, the parent head being compare-and-swapped, and the finalizer. The hub runs
|
|
20
|
+
* the authoritative CAS+lock+gates. When `signWith` is given the request is signed so a
|
|
21
|
+
* gated hub can authenticate the finalizer. Returns the HTTP status + the hub's verdict.
|
|
22
|
+
*/
|
|
23
|
+
export declare function finalizeOnHub(hubUrl: string, args: {
|
|
24
|
+
view: string;
|
|
25
|
+
newCheckpoint: string;
|
|
26
|
+
parentHead: string | null;
|
|
27
|
+
by: string;
|
|
28
|
+
signWith?: {
|
|
29
|
+
keyId: string;
|
|
30
|
+
privateKey: string;
|
|
31
|
+
};
|
|
32
|
+
}): Promise<{
|
|
33
|
+
status: number;
|
|
34
|
+
finalized: boolean;
|
|
35
|
+
head?: string;
|
|
36
|
+
reason?: string;
|
|
37
|
+
}>;
|
|
38
|
+
//# sourceMappingURL=hubClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hubClient.d.ts","sourceRoot":"","sources":["../../src/hub/hubClient.ts"],"names":[],"mappings":"AAsDA;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuBnH;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAsCnG;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACrI,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAWjF"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Network object-gossip client against an AVCS hub (see hubServer.ts).
|
|
2
|
+
//
|
|
3
|
+
// Content-addressed union semantics, mirroring Repo.pull: only transfer what's missing,
|
|
4
|
+
// never mutate an existing object. push = send objects the hub lacks; pull = fetch
|
|
5
|
+
// objects we lack. Uses the global fetch available in Node 22.
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { ObjectStore } from "../store/objectStore.js";
|
|
10
|
+
import { keysOf } from "../reducer/reducer.js";
|
|
11
|
+
/** GET /have → the set of oids the hub holds. */
|
|
12
|
+
async function hubHave(hubUrl) {
|
|
13
|
+
const res = await fetch(`${hubUrl.replace(/\/$/, "")}/have`);
|
|
14
|
+
if (!res.ok)
|
|
15
|
+
throw new Error(`GET /have failed: ${res.status} ${res.statusText}`);
|
|
16
|
+
const oids = (await res.json());
|
|
17
|
+
return new Set(oids);
|
|
18
|
+
}
|
|
19
|
+
/** Per-hub sync cursors persisted under .avcs/sync-cursors.json (E5). */
|
|
20
|
+
async function readCursors(root) {
|
|
21
|
+
const p = join(root, "sync-cursors.json");
|
|
22
|
+
if (!existsSync(p))
|
|
23
|
+
return {};
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(await readFile(p, "utf8"));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Discover the oids to consider pulling. Tries the incremental `GET /sync?since=N`
|
|
33
|
+
* endpoint (E5): only the oids appended since the client's last cursor, plus the new
|
|
34
|
+
* cursor. Falls back to the full `GET /have` against an older hub (cursor stays null).
|
|
35
|
+
* Correctness never depends on the cursor — a wrong/stale one at worst transfers more.
|
|
36
|
+
*/
|
|
37
|
+
async function discover(base, since) {
|
|
38
|
+
try {
|
|
39
|
+
const res = await fetch(`${base}/sync?since=${since}`);
|
|
40
|
+
if (res.ok) {
|
|
41
|
+
const j = (await res.json());
|
|
42
|
+
return { oids: j.oids, cursor: j.cursor };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// fall through to /have
|
|
47
|
+
}
|
|
48
|
+
return { oids: [...(await hubHave(base))], cursor: null };
|
|
49
|
+
}
|
|
50
|
+
/** Mirror Repo.pull's import side-effect: maintain the entity index for imported ops. */
|
|
51
|
+
async function indexIfOperation(store, obj, oid) {
|
|
52
|
+
if (obj.type === "operation") {
|
|
53
|
+
for (const k of keysOf(obj))
|
|
54
|
+
await store.appendEntityIndex(k, oid);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Push objects the hub lacks: diff our local oids against GET /have and POST the
|
|
59
|
+
* missing ones. Private (stash) ops are local-only and never gossiped — same rule as
|
|
60
|
+
* Repo.pull. Returns how many objects were pushed.
|
|
61
|
+
*/
|
|
62
|
+
export async function pushToHub(localRepoDir, hubUrl) {
|
|
63
|
+
const base = hubUrl.replace(/\/$/, "");
|
|
64
|
+
const store = new ObjectStore(localRepoDir);
|
|
65
|
+
const have = await hubHave(base);
|
|
66
|
+
let pushed = 0;
|
|
67
|
+
let rejected = 0;
|
|
68
|
+
for await (const obj of store.list()) {
|
|
69
|
+
const oid = obj.oid;
|
|
70
|
+
if (have.has(oid))
|
|
71
|
+
continue;
|
|
72
|
+
if (obj.type === "operation" && obj.private)
|
|
73
|
+
continue; // stash stays local
|
|
74
|
+
const res = await fetch(`${base}/objects`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: { "content-type": "application/json" },
|
|
77
|
+
body: JSON.stringify(obj),
|
|
78
|
+
});
|
|
79
|
+
if (res.status === 403) {
|
|
80
|
+
rejected++; // gated hub refused an unauthorized op
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!res.ok)
|
|
84
|
+
throw new Error(`POST /objects failed for ${oid}: ${res.status} ${res.statusText}`);
|
|
85
|
+
pushed++;
|
|
86
|
+
}
|
|
87
|
+
return { pushed, rejected };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Pull objects the local store lacks: GET /have, then GET each missing /objects/:oid
|
|
91
|
+
* and put it locally (idempotent, content-addressed). Returns how many were pulled.
|
|
92
|
+
*/
|
|
93
|
+
export async function pullFromHub(localRepoDir, hubUrl) {
|
|
94
|
+
const base = hubUrl.replace(/\/$/, "");
|
|
95
|
+
const store = new ObjectStore(localRepoDir);
|
|
96
|
+
await store.init(); // tolerate a fresh local repo dir
|
|
97
|
+
// Incremental discovery (E5): only consider oids the hub added since our last pull.
|
|
98
|
+
const cursors = await readCursors(store.root);
|
|
99
|
+
const since = cursors[base] ?? 0;
|
|
100
|
+
const { oids, cursor } = await discover(base, since);
|
|
101
|
+
let pulled = 0;
|
|
102
|
+
for (const oid of oids) {
|
|
103
|
+
if (await store.has(oid))
|
|
104
|
+
continue;
|
|
105
|
+
const res = await fetch(`${base}/objects/${encodeURIComponent(oid)}`);
|
|
106
|
+
if (res.status === 404)
|
|
107
|
+
continue; // raced eviction; skip
|
|
108
|
+
if (!res.ok)
|
|
109
|
+
throw new Error(`GET /objects/${oid} failed: ${res.status} ${res.statusText}`);
|
|
110
|
+
const obj = (await res.json());
|
|
111
|
+
await store.put(obj);
|
|
112
|
+
await indexIfOperation(store, obj, oid);
|
|
113
|
+
pulled++;
|
|
114
|
+
}
|
|
115
|
+
// Advance the cursor only after the loop completed (a throw aborts before this, so a
|
|
116
|
+
// failed pull retries from the same cursor next time — never a permanent miss).
|
|
117
|
+
if (cursor !== null) {
|
|
118
|
+
cursors[base] = cursor;
|
|
119
|
+
await store.writeAux("sync-cursors.json", JSON.stringify(cursors));
|
|
120
|
+
}
|
|
121
|
+
// Governance distribution: adopt the hub's authoritative governance refs (policy,
|
|
122
|
+
// membership, protection, protected heads). The objects they point to were just
|
|
123
|
+
// pulled above, so the refs resolve. Working refs (view:*/checkpoint:*) stay local.
|
|
124
|
+
const refsRes = await fetch(`${base}/refs`);
|
|
125
|
+
if (refsRes.ok) {
|
|
126
|
+
const { refs } = (await refsRes.json());
|
|
127
|
+
for (const [name, refOid] of Object.entries(refs)) {
|
|
128
|
+
if (!/^(policy$|member:|protection:|head:)/.test(name))
|
|
129
|
+
continue;
|
|
130
|
+
if (await store.has(refOid))
|
|
131
|
+
await store.setRef(name, refOid);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Propagate redactions: evict plaintext for blobs redacted after we pulled them.
|
|
135
|
+
const { applyRedactions } = await import("./../store/applyRedactions.js");
|
|
136
|
+
await applyRedactions(store);
|
|
137
|
+
return { pulled };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Request a finalize (= PR merge) on the hub (E6): POST /finalize with the view, the new
|
|
141
|
+
* checkpoint, the parent head being compare-and-swapped, and the finalizer. The hub runs
|
|
142
|
+
* the authoritative CAS+lock+gates. When `signWith` is given the request is signed so a
|
|
143
|
+
* gated hub can authenticate the finalizer. Returns the HTTP status + the hub's verdict.
|
|
144
|
+
*/
|
|
145
|
+
export async function finalizeOnHub(hubUrl, args) {
|
|
146
|
+
const base = hubUrl.replace(/\/$/, "");
|
|
147
|
+
const body = { view: args.view, newCheckpoint: args.newCheckpoint, parentHead: args.parentHead, by: args.by };
|
|
148
|
+
if (args.signWith) {
|
|
149
|
+
const { signMessage } = await import("../core/identity.js");
|
|
150
|
+
const msg = `finalize:${args.view}:${args.newCheckpoint}:${args.parentHead ?? ""}`;
|
|
151
|
+
body.sig = { keyId: args.signWith.keyId, alg: "ed25519", sig: signMessage(args.signWith.privateKey, msg) };
|
|
152
|
+
}
|
|
153
|
+
const res = await fetch(`${base}/finalize`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
|
|
154
|
+
const j = (await res.json().catch(() => ({})));
|
|
155
|
+
return { status: res.status, finalized: j.finalized ?? false, head: j.head, reason: j.reason };
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=hubClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hubClient.js","sourceRoot":"","sources":["../../src/hub/hubClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Logger } from "../observe/logger.ts";
|
|
2
|
+
import { Metrics } from "../observe/metrics.ts";
|
|
3
|
+
/** Wire-protocol version the hub speaks (have/objects/refs gossip). Bumped on breaking changes. */
|
|
4
|
+
export declare const HUB_PROTOCOL_VERSION = 1;
|
|
5
|
+
export interface HubHandle {
|
|
6
|
+
url: string;
|
|
7
|
+
port: number;
|
|
8
|
+
metrics: Metrics;
|
|
9
|
+
close(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Start an HTTP hub backed by `new ObjectStore(opts.repoDir)`. The store is init()'d
|
|
13
|
+
* so an empty repo dir works. Pass `port: 0` (or omit) to get an OS-assigned port,
|
|
14
|
+
* read back from the returned handle.
|
|
15
|
+
*/
|
|
16
|
+
export declare function startHub(opts: {
|
|
17
|
+
repoDir: string;
|
|
18
|
+
port?: number;
|
|
19
|
+
gated?: boolean;
|
|
20
|
+
logger?: Logger;
|
|
21
|
+
metrics?: Metrics;
|
|
22
|
+
/** App-layer per-actor push quota (E7). Omit to disable. */
|
|
23
|
+
rateLimit?: {
|
|
24
|
+
maxPerWindow: number;
|
|
25
|
+
windowMs?: number;
|
|
26
|
+
};
|
|
27
|
+
}): Promise<HubHandle>;
|
|
28
|
+
//# sourceMappingURL=hubServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hubServer.d.ts","sourceRoot":"","sources":["../../src/hub/hubServer.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAOhD,mGAAmG;AACnG,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAgFD;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IACpF,4DAA4D;IAC5D,SAAS,CAAC,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD,GAAG,OAAO,CAAC,SAAS,CAAC,CAiErB"}
|