@agenticprimitives/estate-projection 0.0.0-alpha.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Agentic Trust Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # @agenticprimitives/estate-projection
2
+
3
+ An estate's public projection of its authority — spec 410 §4.
4
+
5
+ Grants and relationships are enforced on an estate's own chain and kept in its principals' vaults. A verifier in
6
+ another estate cannot read either. What the estate publishes is two Merkle roots over blinded commitments: the
7
+ **live-grant root** (every grant currently live) and the **membership root** (every countersigned relationship
8
+ credential). They are anchored on public ground with a monotonic sequence, signed by the estate's governance.
9
+
10
+ A holder presents one leaf with its opening and a proof. A verifier in another estate checks it against the roots
11
+ it reads from the anchor and learns exactly one thing: this subject holds a live grant, or is a member, in that
12
+ estate as of that sequence. It learns nothing else — not the terms, not the counterparty, not any other leaf.
13
+
14
+ ```ts
15
+ import { buildProjection, makeAuthorityPresentation, verifyAuthorityPresentation } from '@agenticprimitives/estate-projection';
16
+
17
+ const projection = buildProjection({ chainId: 34348, governance, sequence: 7, liveGrants, memberships });
18
+ // … the estate signs projectionDigest(projection) and anchors the roots on public ground …
19
+ const pres = makeAuthorityPresentation(projection, 'membership', credentialDigest, { nonce, audience });
20
+ const verdict = verifyAuthorityPresentation(pres, rootsReadFromTheRegistry, { subject, nonce, audience, now, maxAgeSeconds: 3600 });
21
+ ```
22
+
23
+ Evidence, never authority: whether the receiving estate lets the agent act is its own mandate, verified per step.
24
+ An inclusion proof over the live set, deliberately — a revocation is a removal and a new root.
@@ -0,0 +1,6 @@
1
+ export declare const PACKAGE_NAME = "@agenticprimitives/estate-projection";
2
+ export declare const PACKAGE_STATUS = "w3-merkle-presentation";
3
+ export declare const SPEC_REF = "specs/410-thesis-review-ten-additions.md";
4
+ export { commitmentOf, buildProjection, projectionDigest, estateIdOf, type EstateProjectionV1, type ProjectionLeafV1, type ProjectionSet, } from './projection.js';
5
+ export { makeAuthorityPresentation, verifyAuthorityPresentation, type AuthorityPresentationV1, type AnchoredRoots, type PresentationVerdict, } from './presentation.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,YAAY,yCAAyC,CAAC;AACnE,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,QAAQ,6CAA6C,CAAC;AAEnE,OAAO,EACL,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,UAAU,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,GAChI,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,yBAAyB,EAAE,2BAA2B,EAAE,KAAK,uBAAuB,EAAE,KAAK,aAAa,EAAE,KAAK,mBAAmB,GACnI,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ // @agenticprimitives/estate-projection — spec 410 §4 (THESIS-4 / THESIS-9).
2
+ //
3
+ // AN ESTATE PROJECTS ITS AUTHORITY ONTO PUBLIC GROUND. Grants and relationships live on the estate's own chain and
4
+ // in its principals' vaults, where a verifier outside the estate cannot read them. What the estate publishes is two
5
+ // Merkle roots over BLINDED COMMITMENTS — the live-grant root (every grant currently live: issued, unexpired,
6
+ // unrevoked, epoch-current) and the membership root (every countersigned relationship credential) — signed by the
7
+ // estate's governance and anchored in `EstateProjectionRegistry.sol` on public ground with a monotonic sequence.
8
+ //
9
+ // A holder presents ONE leaf with its opening and a proof; a verifier in another estate checks it against the root
10
+ // it READS from the registry and learns: this subject holds a live grant / is a member in estate E as of sequence N.
11
+ // It does not learn the grant's terms, the counterparty, or any other leaf. An inclusion proof over the LIVE set,
12
+ // deliberately: a revocation is a removal and a new root, and the sorted-tree non-membership construction is not
13
+ // needed. Resolution / evidence, NEVER authority (ADR-0056 / ADR-0057): whether the receiving estate lets the agent
14
+ // ACT is its own mandate, verified per step.
15
+ export const PACKAGE_NAME = '@agenticprimitives/estate-projection';
16
+ export const PACKAGE_STATUS = 'w3-merkle-presentation';
17
+ export const SPEC_REF = 'specs/410-thesis-review-ten-additions.md';
18
+ export { commitmentOf, buildProjection, projectionDigest, estateIdOf, } from './projection.js';
19
+ export { makeAuthorityPresentation, verifyAuthorityPresentation, } from './presentation.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,mHAAmH;AACnH,oHAAoH;AACpH,8GAA8G;AAC9G,kHAAkH;AAClH,iHAAiH;AACjH,EAAE;AACF,mHAAmH;AACnH,qHAAqH;AACrH,kHAAkH;AAClH,iHAAiH;AACjH,oHAAoH;AACpH,6CAA6C;AAC7C,MAAM,CAAC,MAAM,YAAY,GAAG,sCAAsC,CAAC;AACnE,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,QAAQ,GAAG,0CAA0C,CAAC;AAEnE,OAAO,EACL,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,UAAU,GAC5D,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,yBAAyB,EAAE,2BAA2B,GACvD,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type { Hex } from 'viem';
2
+ import { type EstateProjectionV1, type ProjectionSet } from './projection.js';
3
+ /**
4
+ * `authority-presentation-v1` — what a holder shows a verifier in ANOTHER estate: one leaf, its opening, a proof, the
5
+ * root it is against and the sequence that root was anchored under. `suite` names the construction; a verifier that
6
+ * accepts one need not accept another (`zk-membership-v1` is reserved: the same claim without the opening).
7
+ */
8
+ export interface AuthorityPresentationV1 {
9
+ type: 'ap.authority-presentation.v1';
10
+ suite: 'merkle-membership-v1' | 'zk-membership-v1';
11
+ estateId: Hex;
12
+ set: ProjectionSet;
13
+ sequence: number;
14
+ /** The leaf's opening: the grant hash / credential digest and the blind. Absent under the zk suite. */
15
+ opening?: {
16
+ digest: Hex;
17
+ blind: Hex;
18
+ };
19
+ commitment: Hex;
20
+ proof: Hex[];
21
+ /** Whom this is about — the verifier binds it to the party in front of it. */
22
+ subject: `0x${string}`;
23
+ /** Replay bounds, set by the verifier's challenge. */
24
+ nonce: Hex;
25
+ audience: string;
26
+ }
27
+ export declare function makeAuthorityPresentation(p: EstateProjectionV1, set: ProjectionSet, digest: Hex, challenge: {
28
+ nonce: Hex;
29
+ audience: string;
30
+ }): AuthorityPresentationV1 | null;
31
+ /** What the verifier READ from `EstateProjectionRegistry` on public ground — the live original, never the presentation's word. */
32
+ export interface AnchoredRoots {
33
+ estateId: Hex;
34
+ sequence: number;
35
+ liveGrantRoot: Hex;
36
+ membershipRoot: Hex;
37
+ anchoredAt: number;
38
+ }
39
+ export type PresentationVerdict = {
40
+ ok: true;
41
+ estateId: Hex;
42
+ set: ProjectionSet;
43
+ sequence: number;
44
+ subject: `0x${string}`;
45
+ } | {
46
+ ok: false;
47
+ code: 'suite_unsupported' | 'malformed' | 'estate_mismatch' | 'stale' | 'ahead_of_anchor' | 'opening_mismatch' | 'not_in_root' | 'challenge_mismatch' | 'subject_mismatch';
48
+ reason: string;
49
+ };
50
+ /**
51
+ * Verify against the ANCHORED roots the verifier read itself. The freshness policy is the verifier's: `maxAge`
52
+ * bounds how old the anchored sequence may be; a presentation against a sequence the registry has not anchored
53
+ * is refused, not fetched. Learns `live` / `member`, never "how much" — no score, no ranking (ADR-0056).
54
+ */
55
+ export declare function verifyAuthorityPresentation(pres: AuthorityPresentationV1, anchored: AnchoredRoots, expect: {
56
+ subject: `0x${string}`;
57
+ nonce: Hex;
58
+ audience: string;
59
+ now: number;
60
+ maxAgeSeconds: number;
61
+ }): PresentationVerdict;
62
+ //# sourceMappingURL=presentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../src/presentation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAA0B,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEtG;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,8BAA8B,CAAC;IACrC,KAAK,EAAE,sBAAsB,GAAG,kBAAkB,CAAC;IACnD,QAAQ,EAAE,GAAG,CAAC;IACd,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,uGAAuG;IACvG,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC;IACtC,UAAU,EAAE,GAAG,CAAC;IAChB,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,sDAAsD;IACtD,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,kBAAkB,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE;IAAE,KAAK,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,uBAAuB,GAAG,IAAI,CAI7K;AAED,kIAAkI;AAClI,MAAM,WAAW,aAAa;IAAG,QAAQ,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,GAAG,CAAC;IAAC,cAAc,EAAE,GAAG,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAE/H,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC;IAAC,GAAG,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAA;CAAE,GACzF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,mBAAmB,GAAG,WAAW,GAAG,iBAAiB,GAAG,OAAO,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,aAAa,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9M;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,uBAAuB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE;IAAE,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,mBAAmB,CAa7N"}
@@ -0,0 +1,38 @@
1
+ import { verifyInclusion } from '@agenticprimitives/content-primitives';
2
+ import { commitmentOf, proofFor } from './projection.js';
3
+ export function makeAuthorityPresentation(p, set, digest, challenge) {
4
+ const hit = proofFor(p, set, digest);
5
+ if (!hit)
6
+ return null;
7
+ return { type: 'ap.authority-presentation.v1', suite: 'merkle-membership-v1', estateId: p.estateId, set, sequence: p.sequence, opening: { digest: hit.leaf.digest, blind: hit.leaf.blind }, commitment: hit.leaf.commitment, proof: hit.proof, subject: hit.leaf.subject, nonce: challenge.nonce, audience: challenge.audience };
8
+ }
9
+ /**
10
+ * Verify against the ANCHORED roots the verifier read itself. The freshness policy is the verifier's: `maxAge`
11
+ * bounds how old the anchored sequence may be; a presentation against a sequence the registry has not anchored
12
+ * is refused, not fetched. Learns `live` / `member`, never "how much" — no score, no ranking (ADR-0056).
13
+ */
14
+ export function verifyAuthorityPresentation(pres, anchored, expect) {
15
+ if (pres.type !== 'ap.authority-presentation.v1')
16
+ return { ok: false, code: 'malformed', reason: 'not an authority presentation' };
17
+ if (pres.suite !== 'merkle-membership-v1')
18
+ return { ok: false, code: 'suite_unsupported', reason: `suite ${pres.suite} is not verified here` };
19
+ if (!pres.opening)
20
+ return { ok: false, code: 'malformed', reason: 'the merkle suite needs the opening' };
21
+ if (pres.estateId.toLowerCase() !== anchored.estateId.toLowerCase())
22
+ return { ok: false, code: 'estate_mismatch', reason: 'the presentation names another estate' };
23
+ if (pres.nonce.toLowerCase() !== expect.nonce.toLowerCase() || pres.audience !== expect.audience)
24
+ return { ok: false, code: 'challenge_mismatch', reason: 'the presentation does not answer this challenge' };
25
+ if (pres.subject.toLowerCase() !== expect.subject.toLowerCase())
26
+ return { ok: false, code: 'subject_mismatch', reason: 'the presentation is about someone else' };
27
+ if (pres.sequence !== anchored.sequence)
28
+ return { ok: false, code: pres.sequence > anchored.sequence ? 'ahead_of_anchor' : 'stale', reason: `the presentation is against sequence ${pres.sequence}; the anchor is at ${anchored.sequence}` };
29
+ if (expect.now - anchored.anchoredAt > expect.maxAgeSeconds)
30
+ return { ok: false, code: 'stale', reason: `the anchored projection is older than ${expect.maxAgeSeconds}s` };
31
+ if (commitmentOf(pres.opening.digest, pres.opening.blind).toLowerCase() !== pres.commitment.toLowerCase())
32
+ return { ok: false, code: 'opening_mismatch', reason: 'the opening does not commit to the leaf' };
33
+ const root = pres.set === 'live-grant' ? anchored.liveGrantRoot : anchored.membershipRoot;
34
+ if (!verifyInclusion(pres.commitment, pres.proof, root))
35
+ return { ok: false, code: 'not_in_root', reason: `the leaf is not in the anchored ${pres.set} root` };
36
+ return { ok: true, estateId: pres.estateId, set: pres.set, sequence: pres.sequence, subject: pres.subject };
37
+ }
38
+ //# sourceMappingURL=presentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../src/presentation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { type Hex } from 'viem';
2
+ import { type CorpusTree } from '@agenticprimitives/content-primitives';
3
+ export type ProjectionSet = 'live-grant' | 'membership';
4
+ /** One thing the estate vouches for: a grant hash or a relationship credential digest, blinded. The estate keeps the
5
+ * pair (`digest`, `blind`) so the holder can be handed its opening; only `commitment` reaches the tree. */
6
+ export interface ProjectionLeafV1 {
7
+ set: ProjectionSet;
8
+ /** The delegation hash (live-grant) or the relationship credential digest (membership). */
9
+ digest: Hex;
10
+ /** The holder's 32-byte blind — hands the leaf to the subject without naming it on public ground. */
11
+ blind: Hex;
12
+ /** The subject this leaf is about (the delegate; the member) — kept by the estate, never in the tree. */
13
+ subject: `0x${string}`;
14
+ commitment: Hex;
15
+ }
16
+ /** `keccak256(digest ‖ blind)` — the same construction for both sets, so a verifier's code is one function. */
17
+ export declare function commitmentOf(digest: Hex, blind: Hex): Hex;
18
+ export interface EstateProjectionV1 {
19
+ type: 'ap.estate-projection.v1';
20
+ /** The estate: keccak256 of `eip155:<chainId>:<governance address>` — the one thing public ground learns. */
21
+ estateId: Hex;
22
+ sequence: number;
23
+ liveGrantRoot: Hex;
24
+ membershipRoot: Hex;
25
+ /** The signed charter's hash (spec 410 §9), when the estate has one. */
26
+ charterHash?: Hex;
27
+ builtAt: string;
28
+ /** The leaves, with openings — the ESTATE's record, never published. Ordered as in the trees. */
29
+ leaves: {
30
+ liveGrant: ProjectionLeafV1[];
31
+ membership: ProjectionLeafV1[];
32
+ };
33
+ /** The trees, for handing out proofs. */
34
+ trees: {
35
+ liveGrant: CorpusTree;
36
+ membership: CorpusTree;
37
+ };
38
+ }
39
+ export declare function estateIdOf(chainId: number, governance: `0x${string}`): Hex;
40
+ /** Build both trees from what the estate vouches for right now. Leaves are sorted by commitment so the root is a
41
+ * function of the SET, not of the order the estate happened to list it in. */
42
+ export declare function buildProjection(input: {
43
+ chainId: number;
44
+ governance: `0x${string}`;
45
+ sequence: number;
46
+ charterHash?: Hex;
47
+ now?: () => Date;
48
+ liveGrants: ReadonlyArray<{
49
+ digest: Hex;
50
+ blind: Hex;
51
+ subject: `0x${string}`;
52
+ }>;
53
+ memberships: ReadonlyArray<{
54
+ digest: Hex;
55
+ blind: Hex;
56
+ subject: `0x${string}`;
57
+ }>;
58
+ }): EstateProjectionV1;
59
+ /** What the estate's governance signs before `setRoots`: the registry recomputes nothing, it checks this signature. */
60
+ export declare function projectionDigest(p: Pick<EstateProjectionV1, 'estateId' | 'sequence' | 'liveGrantRoot' | 'membershipRoot' | 'charterHash'>): Hex;
61
+ /** The proof for one leaf, by set and digest. */
62
+ export declare function proofFor(p: EstateProjectionV1, set: ProjectionSet, digest: Hex): {
63
+ leaf: ProjectionLeafV1;
64
+ proof: Hex[];
65
+ } | null;
66
+ //# sourceMappingURL=projection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,uCAAuC,CAAC;AAEtG,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,YAAY,CAAC;AAExD;4GAC4G;AAC5G,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,aAAa,CAAC;IACnB,2FAA2F;IAC3F,MAAM,EAAE,GAAG,CAAC;IACZ,qGAAqG;IACrG,KAAK,EAAE,GAAG,CAAC;IACX,yGAAyG;IACzG,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,GAAG,CAAC;CACjB;AAED,+GAA+G;AAC/G,wBAAgB,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,CAGzD;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,yBAAyB,CAAC;IAChC,6GAA6G;IAC7G,QAAQ,EAAE,GAAG,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,GAAG,CAAC;IACnB,cAAc,EAAE,GAAG,CAAC;IACpB,wEAAwE;IACxE,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,MAAM,EAAE;QAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC;QAAC,UAAU,EAAE,gBAAgB,EAAE,CAAA;KAAE,CAAC;IAC1E,yCAAyC;IACzC,KAAK,EAAE;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,CAAC;CAC1D;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,GAAG,GAAG,CAE1E;AAED;+EAC+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,GAAG,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAClG,UAAU,EAAE,aAAa,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC/E,WAAW,EAAE,aAAa,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACjF,GAAG,kBAAkB,CAWrB;AAED,uHAAuH;AACvH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,UAAU,GAAG,eAAe,GAAG,gBAAgB,GAAG,aAAa,CAAC,GAAG,GAAG,CAG/I;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,kBAAkB,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,GAAG,EAAE,CAAA;CAAE,GAAG,IAAI,CAMhI"}
@@ -0,0 +1,39 @@
1
+ import { keccak256 } from 'viem';
2
+ import { buildCorpusTree, merkleProof } from '@agenticprimitives/content-primitives';
3
+ /** `keccak256(digest ‖ blind)` — the same construction for both sets, so a verifier's code is one function. */
4
+ export function commitmentOf(digest, blind) {
5
+ if (!/^0x[0-9a-fA-F]{64}$/.test(digest) || !/^0x[0-9a-fA-F]{64}$/.test(blind))
6
+ throw new Error('commitmentOf: digest and blind are bytes32');
7
+ return keccak256(`0x${digest.slice(2)}${blind.slice(2)}`);
8
+ }
9
+ export function estateIdOf(chainId, governance) {
10
+ return keccak256(new TextEncoder().encode(`eip155:${chainId}:${governance.toLowerCase()}`));
11
+ }
12
+ /** Build both trees from what the estate vouches for right now. Leaves are sorted by commitment so the root is a
13
+ * function of the SET, not of the order the estate happened to list it in. */
14
+ export function buildProjection(input) {
15
+ const toLeaves = (set, rows) => rows.map((r) => ({ set, digest: r.digest, blind: r.blind, subject: r.subject, commitment: commitmentOf(r.digest, r.blind) })).sort((a, b) => (a.commitment < b.commitment ? -1 : 1));
16
+ const liveGrant = toLeaves('live-grant', input.liveGrants);
17
+ const membership = toLeaves('membership', input.memberships);
18
+ const trees = { liveGrant: buildCorpusTree(liveGrant.map((l) => l.commitment)), membership: buildCorpusTree(membership.map((l) => l.commitment)) };
19
+ return {
20
+ type: 'ap.estate-projection.v1', estateId: estateIdOf(input.chainId, input.governance), sequence: input.sequence,
21
+ liveGrantRoot: trees.liveGrant.root, membershipRoot: trees.membership.root, ...(input.charterHash ? { charterHash: input.charterHash } : {}),
22
+ builtAt: (input.now ?? (() => new Date()))().toISOString(), leaves: { liveGrant, membership }, trees,
23
+ };
24
+ }
25
+ /** What the estate's governance signs before `setRoots`: the registry recomputes nothing, it checks this signature. */
26
+ export function projectionDigest(p) {
27
+ const charter = p.charterHash ?? `0x${'00'.repeat(32)}`;
28
+ return keccak256(`0x${p.estateId.slice(2)}${p.sequence.toString(16).padStart(16, '0')}${p.liveGrantRoot.slice(2)}${p.membershipRoot.slice(2)}${charter.slice(2)}`);
29
+ }
30
+ /** The proof for one leaf, by set and digest. */
31
+ export function proofFor(p, set, digest) {
32
+ const leaves = set === 'live-grant' ? p.leaves.liveGrant : p.leaves.membership;
33
+ const tree = set === 'live-grant' ? p.trees.liveGrant : p.trees.membership;
34
+ const i = leaves.findIndex((l) => l.digest.toLowerCase() === digest.toLowerCase());
35
+ if (i < 0)
36
+ return null;
37
+ return { leaf: leaves[i], proof: merkleProof(tree, i) };
38
+ }
39
+ //# sourceMappingURL=projection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@agenticprimitives/estate-projection",
3
+ "version": "0.0.0-alpha.0",
4
+ "description": "An estate's public projection of its authority (spec 410 §4): the live-grant root and the membership root over blinded commitments, anchored on public ground; the authority presentation a verifier in another estate checks against them, learning that a grant is live or an agent is a member and nothing else.",
5
+ "homepage": "https://agenticprimitives.dev",
6
+ "bugs": {
7
+ "url": "https://github.com/agentictrustlabs/agenticprimitives/issues"
8
+ },
9
+ "author": {
10
+ "name": "Agentic Trust Labs",
11
+ "url": "https://agenticprimitives.dev"
12
+ },
13
+ "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/agentictrustlabs/agenticprimitives.git",
17
+ "directory": "packages/estate-projection"
18
+ },
19
+ "type": "module",
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "LICENSE",
30
+ "dist",
31
+ "README.md"
32
+ ],
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "dependencies": {
37
+ "viem": "^2.52.2",
38
+ "@agenticprimitives/content-primitives": "1.0.0-alpha.27",
39
+ "@agenticprimitives/types": "1.0.0-alpha.26"
40
+ },
41
+ "devDependencies": {
42
+ "vitest": "^4.1.8",
43
+ "@types/node": "^22.7.0"
44
+ },
45
+ "keywords": [
46
+ "agentic",
47
+ "primitives",
48
+ "estate",
49
+ "merkle",
50
+ "presentation",
51
+ "agentic-primitives",
52
+ "agenticprimitives",
53
+ "ai-agents",
54
+ "agent-authority",
55
+ "agentic-trust"
56
+ ],
57
+ "scripts": {
58
+ "build": "tsc -p tsconfig.build.json",
59
+ "typecheck": "tsc -p tsconfig.json --noEmit",
60
+ "test": "vitest run",
61
+ "test:unit": "vitest run test --passWithNoTests",
62
+ "clean": "rm -rf dist"
63
+ }
64
+ }