@mida-context/sdk 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 +21 -0
- package/README.md +26 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7115 -0
- package/dist/types/api/app.d.ts +99 -0
- package/dist/types/api/auth-pure.d.ts +51 -0
- package/dist/types/api/auth.d.ts +17 -0
- package/dist/types/api/authorize.d.ts +24 -0
- package/dist/types/api/batch-deny.d.ts +22 -0
- package/dist/types/api/batch-routes.d.ts +69 -0
- package/dist/types/api/batch-store.d.ts +96 -0
- package/dist/types/api/batcher.d.ts +220 -0
- package/dist/types/api/browser.d.ts +14 -0
- package/dist/types/api/chain-budget.d.ts +61 -0
- package/dist/types/api/chain-views.d.ts +87 -0
- package/dist/types/api/client.d.ts +295 -0
- package/dist/types/api/deny-overlay.d.ts +81 -0
- package/dist/types/api/errors.d.ts +30 -0
- package/dist/types/api/file-stores.d.ts +7 -0
- package/dist/types/api/index.d.ts +17 -0
- package/dist/types/api/secure-fs.d.ts +12 -0
- package/dist/types/api/store.d.ts +51 -0
- package/dist/types/api/stores.d.ts +171 -0
- package/dist/types/api/verify-assertion.d.ts +22 -0
- package/dist/types/api/wire.d.ts +27 -0
- package/dist/types/chain/abis.d.ts +2125 -0
- package/dist/types/chain/browser.d.ts +20 -0
- package/dist/types/chain/deployment-fs.d.ts +15 -0
- package/dist/types/chain/deployment.d.ts +33 -0
- package/dist/types/chain/deployments.generated.d.ts +1 -0
- package/dist/types/chain/gas.d.ts +47 -0
- package/dist/types/chain/history.d.ts +52 -0
- package/dist/types/chain/index.d.ts +13 -0
- package/dist/types/chain/local.d.ts +34 -0
- package/dist/types/chain/logs.d.ts +62 -0
- package/dist/types/chain/placements.d.ts +92 -0
- package/dist/types/chain/read-scope.d.ts +66 -0
- package/dist/types/chain/registry.d.ts +16 -0
- package/dist/types/chain/sponsored.d.ts +93 -0
- package/dist/types/chain/transport.d.ts +53 -0
- package/dist/types/chain/writes.d.ts +165 -0
- package/dist/types/crypto/aead.d.ts +5 -0
- package/dist/types/crypto/bytes.d.ts +4 -0
- package/dist/types/crypto/derive.d.ts +20 -0
- package/dist/types/crypto/index.d.ts +6 -0
- package/dist/types/crypto/object.d.ts +42 -0
- package/dist/types/crypto/payload.d.ts +21 -0
- package/dist/types/crypto/wraps.d.ts +36 -0
- package/dist/types/grant-advisor/advise.d.ts +23 -0
- package/dist/types/grant-advisor/authority.d.ts +44 -0
- package/dist/types/grant-advisor/index.d.ts +5 -0
- package/dist/types/grant-advisor/manifest.d.ts +66 -0
- package/dist/types/grant-advisor/policy.d.ts +91 -0
- package/dist/types/grant-advisor/signatures.d.ts +10 -0
- package/dist/types/mida-context-sdk/daemon.d.ts +27 -0
- package/dist/types/mida-context-sdk/errors.d.ts +27 -0
- package/dist/types/mida-context-sdk/index.d.ts +5 -0
- package/dist/types/mida-context-sdk/local.d.ts +40 -0
- package/dist/types/mida-context-sdk/mida.d.ts +65 -0
- package/dist/types/mida-context-sdk/transport.d.ts +137 -0
- package/dist/types/protocol/batch.d.ts +161 -0
- package/dist/types/protocol/constants.d.ts +56 -0
- package/dist/types/protocol/errors.d.ts +15 -0
- package/dist/types/protocol/ids.d.ts +72 -0
- package/dist/types/protocol/index.d.ts +11 -0
- package/dist/types/protocol/namespaces.d.ts +15 -0
- package/dist/types/protocol/owner-link.d.ts +146 -0
- package/dist/types/protocol/typed-data.d.ts +365 -0
- package/dist/types/protocol/types.d.ts +215 -0
- package/dist/types/protocol/webauthn-assertion.d.ts +29 -0
- package/dist/types/protocol/wire.d.ts +8 -0
- package/dist/types/sdk/agent.d.ts +279 -0
- package/dist/types/sdk/batched.d.ts +68 -0
- package/dist/types/sdk/connect.d.ts +88 -0
- package/dist/types/sdk/index.d.ts +7 -0
- package/dist/types/sdk/request-store.d.ts +26 -0
- package/dist/types/storage/index.d.ts +23 -0
- package/package.json +50 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { Address, Hex } from "viem";
|
|
2
|
+
import type { ContextKind, Permission, ProvenancePolicy, ProvenanceSource, RecordRelation } from "./constants.js";
|
|
3
|
+
export type { Address, Hex };
|
|
4
|
+
/** §4.3 */
|
|
5
|
+
export interface AgentRecord {
|
|
6
|
+
agentId: Hex;
|
|
7
|
+
operator: Address;
|
|
8
|
+
signer: Address;
|
|
9
|
+
encryptionPublicKey: Hex;
|
|
10
|
+
encryptionKeyVersion: number;
|
|
11
|
+
callbackOriginHash: Hex;
|
|
12
|
+
capabilityManifestHash: Hex;
|
|
13
|
+
capabilityManifestVersion: number;
|
|
14
|
+
active: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** §7.2 */
|
|
17
|
+
export interface ReadEpochState {
|
|
18
|
+
readEpoch: bigint;
|
|
19
|
+
publicKey: Hex;
|
|
20
|
+
writeDeadline: bigint;
|
|
21
|
+
}
|
|
22
|
+
/** §8.2 */
|
|
23
|
+
export interface RecordReference {
|
|
24
|
+
relation: RecordRelation;
|
|
25
|
+
recordId: Hex;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Where a migrated record came from — sealed beside or inside the payload by `mida migrate`.
|
|
29
|
+
* Declared here because ContextPayload carries it; `@mida/checkpoint` holds an identical
|
|
30
|
+
* declaration beside StoredCheckpoint (that package stays dependency-free), and the two are
|
|
31
|
+
* structurally interchangeable.
|
|
32
|
+
*/
|
|
33
|
+
export interface MigrationEnvelope {
|
|
34
|
+
version: 1;
|
|
35
|
+
/** The chain the record was copied from, as a decimal string. */
|
|
36
|
+
originalChainId: string;
|
|
37
|
+
/** The ContextRegistry the record lived on before the move. */
|
|
38
|
+
originalContract: Address;
|
|
39
|
+
originalRecordId: Hex;
|
|
40
|
+
/** The old record's on-chain manifestHash. */
|
|
41
|
+
originalCommitment: Hex;
|
|
42
|
+
/** The old record's on-chain author id. */
|
|
43
|
+
originalAuthor: Hex;
|
|
44
|
+
/** When the record was first written — ISO-8601. */
|
|
45
|
+
originalCreatedAt: string;
|
|
46
|
+
/** When the move happened — ISO-8601; its day is what "(moved on …)" renders. */
|
|
47
|
+
migratedAt: string;
|
|
48
|
+
}
|
|
49
|
+
export interface ContextPayload {
|
|
50
|
+
v: 1;
|
|
51
|
+
value: string | Record<string, unknown>;
|
|
52
|
+
kind: ContextKind;
|
|
53
|
+
provenance: {
|
|
54
|
+
source: ProvenanceSource;
|
|
55
|
+
extractionConfidence?: number;
|
|
56
|
+
references?: RecordReference[];
|
|
57
|
+
sourceHash?: Hex;
|
|
58
|
+
sourceUri?: string;
|
|
59
|
+
retrievedAt?: number;
|
|
60
|
+
note?: string;
|
|
61
|
+
};
|
|
62
|
+
tags?: string[];
|
|
63
|
+
/**
|
|
64
|
+
* The migration envelope of a moved record whose `value` is a string — a string cannot carry
|
|
65
|
+
* the envelope inside, so it sits here, a sibling of `value`. An object `value` carries it at
|
|
66
|
+
* `value.migration` instead, and an ordinary record carries no `migration` key at all.
|
|
67
|
+
*/
|
|
68
|
+
migration?: MigrationEnvelope;
|
|
69
|
+
}
|
|
70
|
+
/** §8.3 */
|
|
71
|
+
export interface EpochDEKWrap {
|
|
72
|
+
v: 1;
|
|
73
|
+
contextId: Hex;
|
|
74
|
+
namespaceId: Hex;
|
|
75
|
+
readEpoch: string;
|
|
76
|
+
ephemeralPublicKey: Hex;
|
|
77
|
+
nonce: Hex;
|
|
78
|
+
wrappedDek: Hex;
|
|
79
|
+
}
|
|
80
|
+
/** §8.4 */
|
|
81
|
+
export interface ReaderEpochWrap {
|
|
82
|
+
v: 1;
|
|
83
|
+
owner: Address;
|
|
84
|
+
namespaceId: Hex;
|
|
85
|
+
readEpoch: string;
|
|
86
|
+
agentId: Hex;
|
|
87
|
+
agentKeyVersion: number;
|
|
88
|
+
ephemeralPublicKey: Hex;
|
|
89
|
+
nonce: Hex;
|
|
90
|
+
wrappedEpochPrivateKey: Hex;
|
|
91
|
+
createdAt: string;
|
|
92
|
+
}
|
|
93
|
+
/** §9.1 */
|
|
94
|
+
export interface ObjectManifest {
|
|
95
|
+
v: 1;
|
|
96
|
+
contextId: Hex;
|
|
97
|
+
ciphertextHash: Hex;
|
|
98
|
+
ciphertextSize: number;
|
|
99
|
+
payloadNonce: Hex;
|
|
100
|
+
cryptoVersion: "mida-crypto-v1";
|
|
101
|
+
readEpoch: string;
|
|
102
|
+
epochDekWrap: EpochDEKWrap;
|
|
103
|
+
}
|
|
104
|
+
/** §9.2 */
|
|
105
|
+
export interface StorageRef {
|
|
106
|
+
provider: "memory" | "fs" | "mida-api" | "s3" | "ipfs";
|
|
107
|
+
locator: string;
|
|
108
|
+
}
|
|
109
|
+
/** §13.2. GrantScope (§10.4) has the same three fields. */
|
|
110
|
+
export interface RequestedScope {
|
|
111
|
+
namespaceId: Hex;
|
|
112
|
+
permissions: number;
|
|
113
|
+
provenancePolicy: number;
|
|
114
|
+
}
|
|
115
|
+
export type GrantScope = RequestedScope;
|
|
116
|
+
export type PurposeId = "general_assistance" | "career_coaching" | "project_assistance" | "travel_planning";
|
|
117
|
+
export interface AccessRequest {
|
|
118
|
+
v: 1;
|
|
119
|
+
chainId: string;
|
|
120
|
+
capabilityRegistry: Address;
|
|
121
|
+
requestId: Hex;
|
|
122
|
+
nonce: Hex;
|
|
123
|
+
agentId: Hex;
|
|
124
|
+
purposeId: PurposeId;
|
|
125
|
+
callbackOrigin: string;
|
|
126
|
+
manifestHash: Hex;
|
|
127
|
+
manifestVersion: number;
|
|
128
|
+
policyVersion: "mida-grant-policy-v1";
|
|
129
|
+
namespaceTreeVersion: "mida-namespace-tree-v1";
|
|
130
|
+
scopes: RequestedScope[];
|
|
131
|
+
issuedAt: string;
|
|
132
|
+
requestExpiresAt: string;
|
|
133
|
+
capabilityExpiresAt: string;
|
|
134
|
+
agentSignature: Hex;
|
|
135
|
+
}
|
|
136
|
+
export interface GrantedCapability {
|
|
137
|
+
namespaceId: Hex;
|
|
138
|
+
permissions: number;
|
|
139
|
+
provenancePolicy: number;
|
|
140
|
+
expiresAt: string;
|
|
141
|
+
capabilityId: Hex;
|
|
142
|
+
transactionHash: Hex;
|
|
143
|
+
}
|
|
144
|
+
export interface AccessGrantResponse {
|
|
145
|
+
v: 1;
|
|
146
|
+
chainId: string;
|
|
147
|
+
capabilityRegistry: Address;
|
|
148
|
+
requestId: Hex;
|
|
149
|
+
nonce: Hex;
|
|
150
|
+
requestHash: Hex;
|
|
151
|
+
owner: Address;
|
|
152
|
+
agentId: Hex;
|
|
153
|
+
manifestHash: Hex;
|
|
154
|
+
manifestVersion: number;
|
|
155
|
+
policyVersion: "mida-grant-policy-v1";
|
|
156
|
+
namespaceTreeVersion: "mida-namespace-tree-v1";
|
|
157
|
+
capabilities: GrantedCapability[];
|
|
158
|
+
}
|
|
159
|
+
/** §14.1 */
|
|
160
|
+
export interface PurposeDeclaration {
|
|
161
|
+
id: PurposeId;
|
|
162
|
+
description: string;
|
|
163
|
+
}
|
|
164
|
+
export interface ScopeDeclaration {
|
|
165
|
+
purposeId: PurposeId;
|
|
166
|
+
namespace: string;
|
|
167
|
+
permissions: Permission[];
|
|
168
|
+
provenancePolicies?: ProvenancePolicy[];
|
|
169
|
+
reason: string;
|
|
170
|
+
}
|
|
171
|
+
export interface AgentCapabilityManifestBody {
|
|
172
|
+
v: 1;
|
|
173
|
+
agentId: Hex;
|
|
174
|
+
manifestVersion: number;
|
|
175
|
+
name: string;
|
|
176
|
+
purposes: PurposeDeclaration[];
|
|
177
|
+
scopeDeclarations: ScopeDeclaration[];
|
|
178
|
+
issuedAt: number;
|
|
179
|
+
}
|
|
180
|
+
export interface SignedAgentCapabilityManifest {
|
|
181
|
+
manifest: AgentCapabilityManifestBody;
|
|
182
|
+
operatorSignature: Hex;
|
|
183
|
+
}
|
|
184
|
+
/** §14.5 */
|
|
185
|
+
export interface EffectiveAuthority {
|
|
186
|
+
namespaceId: Hex;
|
|
187
|
+
permission: Permission;
|
|
188
|
+
provenancePolicy?: ProvenancePolicy;
|
|
189
|
+
}
|
|
190
|
+
export interface OwnerAgentHistory {
|
|
191
|
+
owner: Address;
|
|
192
|
+
agentId: Hex;
|
|
193
|
+
previouslyRevoked: boolean;
|
|
194
|
+
observedThroughBlock: bigint;
|
|
195
|
+
}
|
|
196
|
+
/** §14.6 */
|
|
197
|
+
export type ScopeWarningCode = "SCOPE_NOT_DECLARED" | "SCOPE_UNCLASSIFIED" | "SCOPE_ELEVATED" | "SCOPE_SUSPICIOUS" | "HIGH_SENSITIVITY" | "BROAD_PARENT_SCOPE" | "SUPERSEDE_ANY_EXPLICIT" | "PERMISSION_NARROWED" | "PROVENANCE_POLICY_NARROWED" | "DURATION_NARROWED" | "PREVIOUSLY_REVOKED";
|
|
198
|
+
export interface ScopeWarning {
|
|
199
|
+
code: ScopeWarningCode;
|
|
200
|
+
namespaceId?: Hex;
|
|
201
|
+
relatedNamespaceIds?: Hex[];
|
|
202
|
+
severity: "info" | "warning" | "critical";
|
|
203
|
+
messageKey: string;
|
|
204
|
+
}
|
|
205
|
+
export interface GrantAdvice {
|
|
206
|
+
policyVersion: "mida-grant-policy-v1";
|
|
207
|
+
namespaceTreeVersion: "mida-namespace-tree-v1";
|
|
208
|
+
requestHash: Hex;
|
|
209
|
+
manifestHash: Hex;
|
|
210
|
+
manifestVersion: number;
|
|
211
|
+
recommended: RequestedScope[];
|
|
212
|
+
recommendedExpiresAt: string;
|
|
213
|
+
warnings: ScopeWarning[];
|
|
214
|
+
risk: "low" | "medium" | "high";
|
|
215
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Hex } from "viem";
|
|
2
|
+
/** Order of the P256 (secp256r1) group. */
|
|
3
|
+
export declare const P256_N = 115792089210356248762697446949407573529996955224135760342422259061068512044369n;
|
|
4
|
+
/** Solidity `WebAuthn.WebAuthnAuth` from webauthn-sol v1.0.0, in field order. */
|
|
5
|
+
export interface WebAuthnAuthStruct {
|
|
6
|
+
authenticatorData: Hex;
|
|
7
|
+
clientDataJSON: string;
|
|
8
|
+
challengeIndex: bigint;
|
|
9
|
+
typeIndex: bigint;
|
|
10
|
+
r: bigint;
|
|
11
|
+
s: bigint;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* EIP-7951 accepts any 0 < s < n, but webauthn-sol rejects s > n/2 (spec §10.4). A valid signature with high s has an
|
|
15
|
+
* equally valid twin at n - s, so every adapter maps to that low-s form before contract submission.
|
|
16
|
+
*/
|
|
17
|
+
export declare function normalizeP256LowS(s: bigint): bigint;
|
|
18
|
+
/**
|
|
19
|
+
* The shared assertion adapter (spec §10.4, §15): builds the struct `grantBatch` and `rotateP256Key` consume, with s
|
|
20
|
+
* normalized. It has no FakeVault or browser dependency, so Project 2's real passkey adapter uses exactly this.
|
|
21
|
+
*/
|
|
22
|
+
export declare function toWebAuthnAuthStruct(input: {
|
|
23
|
+
authenticatorData: Hex;
|
|
24
|
+
clientDataJSON: string;
|
|
25
|
+
challengeIndex: number | bigint;
|
|
26
|
+
typeIndex: number | bigint;
|
|
27
|
+
r: bigint;
|
|
28
|
+
s: bigint;
|
|
29
|
+
}): WebAuthnAuthStruct;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Hex } from "viem";
|
|
2
|
+
export declare const MAX_UINT64: bigint;
|
|
3
|
+
export declare function encodeUint64(value: bigint): string;
|
|
4
|
+
export declare function decodeUint64(value: string): bigint;
|
|
5
|
+
export declare function assertHex(value: string, byteLength: number): Hex;
|
|
6
|
+
export declare function isZeroBytes(bytes: Uint8Array): boolean;
|
|
7
|
+
export declare function canonicalJson(value: unknown): string;
|
|
8
|
+
export declare function canonicalBytes(value: unknown): Uint8Array;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import type { AccessGrantResponse, AccessRequest, Address, ContextKind, ContextPayload, GrantedCapability, Hex, LineagePolicy, ObjectManifest, PurposeId, RecordReference } from "../protocol/index.js";
|
|
2
|
+
import type { LocalWriteContext } from "../chain/index.js";
|
|
3
|
+
import type { ScopeInput } from "../grant-advisor/index.js";
|
|
4
|
+
import type { BatchReceipt, ContextApiRoutes, ContextRecordView } from "../api/index.js";
|
|
5
|
+
import type { AccessRequestStore } from "./request-store.js";
|
|
6
|
+
/** §13.2 allows up to 600 seconds; the SDK uses 300 so a request stays valid through a normal consent screen. */
|
|
7
|
+
export declare const REQUEST_LIFETIME_SECONDS = 300n;
|
|
8
|
+
export interface AccessRequestInput {
|
|
9
|
+
purposeId: PurposeId;
|
|
10
|
+
/** Builder-supplied scopes; parents are expanded through the frozen tree before signing. */
|
|
11
|
+
scopes: readonly ScopeInput[];
|
|
12
|
+
/** Requested grant expiry in Unix seconds; omitted or 0n means no expiry is requested. */
|
|
13
|
+
capabilityExpiresAt?: bigint;
|
|
14
|
+
}
|
|
15
|
+
export interface Grant {
|
|
16
|
+
owner: Address;
|
|
17
|
+
agentId: Hex;
|
|
18
|
+
requestId: Hex;
|
|
19
|
+
capabilities: GrantedCapability[];
|
|
20
|
+
}
|
|
21
|
+
/** The only provenance an agent can write (§11.8). USER_ASSERTED and USER_CONFIRMED need the owner. */
|
|
22
|
+
export type AgentProvenanceSource = "AGENT_INFERRED" | "IMPORTED" | "EXTERNAL_ATTESTATION";
|
|
23
|
+
export interface CreateContextInput {
|
|
24
|
+
value: ContextPayload["value"];
|
|
25
|
+
kind: Exclude<ContextKind, "NONE">;
|
|
26
|
+
source: AgentProvenanceSource;
|
|
27
|
+
references?: RecordReference[];
|
|
28
|
+
tags?: string[];
|
|
29
|
+
note?: string;
|
|
30
|
+
extractionConfidence?: number;
|
|
31
|
+
expiresAt?: bigint;
|
|
32
|
+
}
|
|
33
|
+
export type SupersedeContextInput = CreateContextInput;
|
|
34
|
+
export interface ReadOptions {
|
|
35
|
+
/**
|
|
36
|
+
* `false` skips the same-second placement scan entirely — for a read that never orders its
|
|
37
|
+
* objects (the save duplicate-check). Default: records stamped in the same second get one
|
|
38
|
+
* bounded ±64-block log scan per disjoint window to recover (block, index).
|
|
39
|
+
*/
|
|
40
|
+
placements?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface ProposalInput {
|
|
43
|
+
value: ContextPayload["value"];
|
|
44
|
+
kind?: Exclude<ContextKind, "NONE">;
|
|
45
|
+
references?: RecordReference[];
|
|
46
|
+
tags?: string[];
|
|
47
|
+
note?: string;
|
|
48
|
+
extractionConfidence?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* One record written exactly as given (migrate B1): the payload is sealed verbatim — every
|
|
52
|
+
* provenance field `create` drops survives — and the record type, kind, lineage policy, expiry,
|
|
53
|
+
* parent and nonce are all the caller's. The caller predicts the id with `predictContextId`.
|
|
54
|
+
*/
|
|
55
|
+
export interface ReplayInput {
|
|
56
|
+
namespaceId: Hex;
|
|
57
|
+
payload: ContextPayload;
|
|
58
|
+
recordType: "CONTEXT" | "EVIDENCE";
|
|
59
|
+
kind: ContextKind;
|
|
60
|
+
lineagePolicy: LineagePolicy;
|
|
61
|
+
expiresAt: bigint;
|
|
62
|
+
/** The parent record's contextId, or the zero hash for a root. */
|
|
63
|
+
expectedParentId: Hex;
|
|
64
|
+
/** Prepared by the caller; what makes a re-run land on the same id instead of duplicating. */
|
|
65
|
+
objectNonce: Hex;
|
|
66
|
+
}
|
|
67
|
+
export interface ContextObject {
|
|
68
|
+
contextId: Hex;
|
|
69
|
+
owner: Address;
|
|
70
|
+
namespace: string;
|
|
71
|
+
namespaceId: Hex;
|
|
72
|
+
authorId: Hex;
|
|
73
|
+
lineageId: Hex;
|
|
74
|
+
parentId: Hex;
|
|
75
|
+
version: number;
|
|
76
|
+
readEpoch: bigint;
|
|
77
|
+
recordType: "CONTEXT" | "EVIDENCE";
|
|
78
|
+
payload: ContextPayload;
|
|
79
|
+
transactionHash?: Hex;
|
|
80
|
+
/**
|
|
81
|
+
* The commitment the record's bytes were sealed under: the chain row's manifestHash for an
|
|
82
|
+
* anchored record, the signed batch message's for a pending one. A reader verifies the
|
|
83
|
+
* payload against it — it is never trusted on its own.
|
|
84
|
+
*/
|
|
85
|
+
manifestHash?: Hex;
|
|
86
|
+
/**
|
|
87
|
+
* Monad's own placement of the save — set only on records the chain has actually recorded.
|
|
88
|
+
* `at` is the timestamp the chain stamped (the ContextRegistry row's createdAt for a direct
|
|
89
|
+
* save, the anchor block's time for a batched one); `block`, `transaction` and `index` are
|
|
90
|
+
* its position in the chain's order — the anchoring block, the anchoring transaction's index
|
|
91
|
+
* inside it, then the save's own position inside the transaction (the log index for a direct
|
|
92
|
+
* save, the batch's own position for a batched one). Absent entirely when no chain fact
|
|
93
|
+
* places the record — a pending batched save above all — and `block`/`transaction`/`index`
|
|
94
|
+
* are absent when only the stamp could be recovered. `batchId` names the one batch that
|
|
95
|
+
* anchored a batched-lane save: two rows sharing it share one transaction, so their `index`
|
|
96
|
+
* values are positions in the same ordering and comparable without asking the chain for the
|
|
97
|
+
* transaction index (in-14 F-1). Whatever an object claims inside its own payload never
|
|
98
|
+
* reaches this field.
|
|
99
|
+
*/
|
|
100
|
+
chain?: {
|
|
101
|
+
at: bigint;
|
|
102
|
+
block?: bigint;
|
|
103
|
+
transaction?: number;
|
|
104
|
+
index?: number;
|
|
105
|
+
batchId?: Hex;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* What `sealReplay` produces once and `sendSealed` may send any number of times (migrate B1b): the
|
|
110
|
+
* exact ciphertext and manifest the store's same-manifest repeat upload accepts, plus every field
|
|
111
|
+
* `register` needs. Ciphertext only — no plaintext — so a crash between upload and register
|
|
112
|
+
* resends identical bytes instead of re-sealing (a fresh seal draws a fresh key and a different
|
|
113
|
+
* manifestHash the store then refuses).
|
|
114
|
+
*/
|
|
115
|
+
export interface SealedRecord {
|
|
116
|
+
contextId: Hex;
|
|
117
|
+
namespaceId: Hex;
|
|
118
|
+
readEpoch: bigint;
|
|
119
|
+
manifest: ObjectManifest;
|
|
120
|
+
manifestHash: Hex;
|
|
121
|
+
ciphertext: Uint8Array;
|
|
122
|
+
onChain: {
|
|
123
|
+
recordType: "CONTEXT" | "EVIDENCE";
|
|
124
|
+
kind: ContextKind;
|
|
125
|
+
lineagePolicy: LineagePolicy;
|
|
126
|
+
expiresAt: bigint;
|
|
127
|
+
expectedParentId: Hex;
|
|
128
|
+
evidenceCommitment: Hex;
|
|
129
|
+
objectNonce: Hex;
|
|
130
|
+
provenanceSource: number;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* What `sendSealed` can attest: the anchored record's view plus its transaction — `ContextObject`
|
|
135
|
+
* minus `payload`, because a `SealedRecord` holds no plaintext to put in it (`replay` recomposes
|
|
136
|
+
* the full object from its own input). `transactionHash` is absent when the identical record was
|
|
137
|
+
* already anchored — a resend is done, not sent again.
|
|
138
|
+
*/
|
|
139
|
+
export type SentRecord = Omit<ContextObject, "payload">;
|
|
140
|
+
export interface MidaAgentConfig {
|
|
141
|
+
agentId: Hex;
|
|
142
|
+
callbackOrigin: string;
|
|
143
|
+
encryptionPrivateKey: Uint8Array;
|
|
144
|
+
/** Write context whose account is the agent's current registered signer. */
|
|
145
|
+
chain: LocalWriteContext;
|
|
146
|
+
/** Context API client bound to the same signer. */
|
|
147
|
+
api: ContextApiRoutes & {
|
|
148
|
+
account: {
|
|
149
|
+
address: Address;
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
requests?: AccessRequestStore;
|
|
153
|
+
/**
|
|
154
|
+
* Grants this agent completed in an earlier process. They only tell the agent which capabilityId to present:
|
|
155
|
+
* every read is still authorised by the API against Monad and every write by the contract, so a stale or forged
|
|
156
|
+
* entry buys nothing.
|
|
157
|
+
*/
|
|
158
|
+
grants?: readonly Grant[];
|
|
159
|
+
}
|
|
160
|
+
/** §13.1 agent/server SDK. Every authority it relies on is re-read from Monad; nothing the API returns is trusted alone. */
|
|
161
|
+
export declare class MidaAgent {
|
|
162
|
+
#private;
|
|
163
|
+
readonly agentId: Hex;
|
|
164
|
+
constructor(config: MidaAgentConfig);
|
|
165
|
+
get grants(): readonly Grant[];
|
|
166
|
+
/** The chain's own record for one contextId — null when the registry holds none. */
|
|
167
|
+
chainRecord(contextId: Hex): Promise<ContextRecordView | null>;
|
|
168
|
+
/**
|
|
169
|
+
* Whether Monad lists at least one currently-valid capability for this owner–agent pair —
|
|
170
|
+
* the contract's `isCapabilityValid` answer per id, not the local grant copy.
|
|
171
|
+
*/
|
|
172
|
+
hasLiveCapability(owner: Address): Promise<boolean>;
|
|
173
|
+
/** §13.2: canonical, parent-expanded, sorted exact scopes, signed by the agent's current signer and persisted. */
|
|
174
|
+
createAccessRequest(input: AccessRequestInput): Promise<AccessRequest>;
|
|
175
|
+
/**
|
|
176
|
+
* §13.3: the response must match the stored original request, stay within its authority (Part C helper), and every
|
|
177
|
+
* capability must exist on Monad with identical fields, be currently valid, and be emitted by the named transaction.
|
|
178
|
+
* The chain proves a capability exists; the original request proves it is the one this agent asked for.
|
|
179
|
+
*/
|
|
180
|
+
completeAccessRequest(request: AccessRequest, response: AccessGrantResponse): Promise<Grant>;
|
|
181
|
+
/**
|
|
182
|
+
* §12.3 read: API objects are re-checked against Monad commitments, then decrypted with this
|
|
183
|
+
* agent's own epoch wraps. A list the store could not fully verify is never returned as if it
|
|
184
|
+
* were complete — `read` refuses it outright; callers that can carry the flag use
|
|
185
|
+
* `readWithStatus` instead.
|
|
186
|
+
*/
|
|
187
|
+
read(owner: Address, namespace: string, options?: ReadOptions): Promise<ContextObject[]>;
|
|
188
|
+
/**
|
|
189
|
+
* `read` plus the store's completeness flag, for callers that can surface it downstream (M3-D).
|
|
190
|
+
*
|
|
191
|
+
* Placement policy (in-9 R-1): `chain.at` is already chain truth on every record — the
|
|
192
|
+
* contract stores `block.timestamp` as createdAt — so no log scan runs for it. The event
|
|
193
|
+
* log's (block, index) is needed ONLY to order records stamped in the same second, and only
|
|
194
|
+
* then does the read scan: a bounded ±64-block window around the block that second implies,
|
|
195
|
+
* one getLogs per disjoint window. `{ placements: false }` skips even that (the save
|
|
196
|
+
* duplicate-check needs no ordering at all); a missed window falls back to the contextId
|
|
197
|
+
* tie-break, never to a whole-history scan.
|
|
198
|
+
*/
|
|
199
|
+
readWithStatus(owner: Address, namespace: string, options?: ReadOptions): Promise<{
|
|
200
|
+
objects: ContextObject[];
|
|
201
|
+
partial: boolean;
|
|
202
|
+
}>;
|
|
203
|
+
/**
|
|
204
|
+
* The batched counterpart of `readWithStatus` (Task 4): lists the store's batch rows and verifies
|
|
205
|
+
* each one itself — an anchored row only survives if its proof reaches the on-chain batch root
|
|
206
|
+
* and it is the lineage's current head; a queued/submitted row is checked for everything except
|
|
207
|
+
* inclusion and comes back marked `PENDING_ANCHOR` with its author agentId. The store's word for
|
|
208
|
+
* a row's state is never trusted; every authority check reads the contracts.
|
|
209
|
+
*/
|
|
210
|
+
readBatchedWithStatus(owner: Address, namespace: string): Promise<{
|
|
211
|
+
anchored: ContextObject[];
|
|
212
|
+
pending: (ContextObject & {
|
|
213
|
+
anchor: "PENDING_ANCHOR";
|
|
214
|
+
authorAgentId: Hex;
|
|
215
|
+
receivedAt: number;
|
|
216
|
+
})[];
|
|
217
|
+
skipped: {
|
|
218
|
+
contextId: Hex;
|
|
219
|
+
reason: string;
|
|
220
|
+
}[];
|
|
221
|
+
partial: boolean;
|
|
222
|
+
}>;
|
|
223
|
+
/**
|
|
224
|
+
* The duplicate check behind a save (in-12 N-6): whether this owner+namespace already holds a
|
|
225
|
+
* record whose decrypted payload satisfies `match`. Opening a row is local work — the epoch
|
|
226
|
+
* keys are fetched once per epoch and shared — so every listed row is opened and judged, and
|
|
227
|
+
* chain verification runs ONLY on the (normally zero or one) rows whose payload claims the
|
|
228
|
+
* match. That ordering is safe because a row the store invented cannot reach `match`: without
|
|
229
|
+
* the epoch key it cannot produce ciphertext that opens under the contextId binding, so a
|
|
230
|
+
* payload that opens was sealed honestly. A claimed match is then verified against Monad
|
|
231
|
+
* exactly as the full reads verify it — the store's word never decides "duplicate" — and a
|
|
232
|
+
* match whose record is not really there is skipped, not believed. A partial list still
|
|
233
|
+
* refuses outright: an incomplete view can never answer "not a duplicate" honestly. Returns
|
|
234
|
+
* the matching record's contextId, or undefined.
|
|
235
|
+
*/
|
|
236
|
+
findDuplicate(owner: Address, namespace: string, match: (value: unknown) => boolean, options?: {
|
|
237
|
+
batched?: boolean;
|
|
238
|
+
}): Promise<Hex | undefined>;
|
|
239
|
+
create(owner: Address, namespace: string, input: CreateContextInput): Promise<ContextObject>;
|
|
240
|
+
/**
|
|
241
|
+
* The BatchAnchor write path (Task 4): seals the same checkpoint shape as `create` — a new
|
|
242
|
+
* STANDARD-lineage CONTEXT record, always AGENT_INFERRED — but signs it for the batch queue
|
|
243
|
+
* instead of calling `contexts.register`. The signature is the whole authorization; no
|
|
244
|
+
* transaction leaves this method.
|
|
245
|
+
*/
|
|
246
|
+
createBatched(owner: Address, namespace: string, input: CreateContextInput): Promise<{
|
|
247
|
+
contextId: Hex;
|
|
248
|
+
state: "QUEUED";
|
|
249
|
+
receipt: BatchReceipt;
|
|
250
|
+
}>;
|
|
251
|
+
/** §11.6: SUPERSEDE_ANY on another author's STANDARD lineage, SUPERSEDE_OWN (or ANY) on this agent's own lineage. */
|
|
252
|
+
supersede(owner: Address, parentId: Hex, input: SupersedeContextInput): Promise<ContextObject>;
|
|
253
|
+
/** Always AGENT_INFERRED; the owner decides later whether to confirm it. */
|
|
254
|
+
propose(owner: Address, namespace: string, input: ProposalInput): Promise<ContextObject>;
|
|
255
|
+
/** The contextId a `replay` with this nonce will produce — computed before sending. */
|
|
256
|
+
predictContextId(owner: Address, namespaceId: Hex, objectNonce: Hex): Hex;
|
|
257
|
+
/**
|
|
258
|
+
* Writes one record exactly as given (migrate B1). Unlike `#write` it does not rebuild the
|
|
259
|
+
* payload — `sourceHash`, `sourceUri`, `retrievedAt`, `note`, `extractionConfidence`,
|
|
260
|
+
* `references` and `tags` all reach the seal — and it adds no provenance restriction of its
|
|
261
|
+
* own: the ordinary capability and epoch checks apply, and the contract stays the authority.
|
|
262
|
+
* Seal once, then send those bytes (migrate B1b).
|
|
263
|
+
*/
|
|
264
|
+
replay(owner: Address, input: ReplayInput): Promise<ContextObject>;
|
|
265
|
+
/**
|
|
266
|
+
* Seals a replay exactly once and writes nothing (migrate B1b): the capability, epoch, id and
|
|
267
|
+
* every byte `sendSealed` needs, frozen so a retry — including after a crash between upload and
|
|
268
|
+
* register — resends identical bytes. The epoch is checked here and again at send: a seal that
|
|
269
|
+
* outlives its epoch is refused, never silently resealed under a different epoch.
|
|
270
|
+
*/
|
|
271
|
+
sealReplay(owner: Address, input: ReplayInput): Promise<SealedRecord>;
|
|
272
|
+
/**
|
|
273
|
+
* Sends the bytes `sealReplay` produced — the same bytes on every call (migrate B1b). The store
|
|
274
|
+
* accepts a repeat upload only for an identical manifest, so a resend after an upload-only crash
|
|
275
|
+
* lands; a record already anchored with this exact manifestHash is done, not sent again; a stale
|
|
276
|
+
* epoch refuses `EPOCH_ROTATION_REQUIRED` before anything leaves this process.
|
|
277
|
+
*/
|
|
278
|
+
sendSealed(owner: Address, sealed: SealedRecord): Promise<SentRecord>;
|
|
279
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Address, BatchSaveMessage, Hex } from "../protocol/index.js";
|
|
2
|
+
import type { Deployment } from "../chain/index.js";
|
|
3
|
+
import type { LocalAccount, PublicClient } from "viem";
|
|
4
|
+
import type { BatchedReadItem } from "../api/index.js";
|
|
5
|
+
export type { BatchedItemState, BatchedReadItem, BatchedSaveWire, BatchReceipt } from "../api/index.js";
|
|
6
|
+
/** Every way `verifyBatchedItem` can refuse, in the order the checks run. */
|
|
7
|
+
export type BatchedVerifyReason = "ciphertext" | "manifest" | "signature" | "author" | "not-anchored" | "unknown-batch" | "proof" | "stale";
|
|
8
|
+
/** Every way `verifyPendingItem` can refuse, in the order the checks run. */
|
|
9
|
+
export type PendingVerifyReason = "not-pending" | "ciphertext" | "manifest" | "signature" | "author" | "no-authority";
|
|
10
|
+
/**
|
|
11
|
+
* `anchorBlock` is the block `batchOf` reports for the save's batch — the block the anchor
|
|
12
|
+
* transaction mined in, read from the contract during verification, never the store's word.
|
|
13
|
+
*/
|
|
14
|
+
export type BatchedVerdict = {
|
|
15
|
+
ok: true;
|
|
16
|
+
agentId: Hex;
|
|
17
|
+
anchorBlock: bigint;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
reason: BatchedVerifyReason;
|
|
21
|
+
};
|
|
22
|
+
export type PendingVerdict = {
|
|
23
|
+
ok: true;
|
|
24
|
+
agentId: Hex;
|
|
25
|
+
anchorBlock?: never;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
reason: PendingVerifyReason;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* §BatchAnchor write path: the agent signs one `MidaBatchSaveV1` typed message per save under the
|
|
32
|
+
* BatchAnchor domain; the contract re-derives this digest, so the signature alone is the whole
|
|
33
|
+
* authorization — no transaction leaves this call.
|
|
34
|
+
*/
|
|
35
|
+
export declare function signBatchSave(input: {
|
|
36
|
+
account: LocalAccount;
|
|
37
|
+
chainId: bigint;
|
|
38
|
+
batchAnchor: Address;
|
|
39
|
+
message: BatchSaveMessage;
|
|
40
|
+
}): Promise<Hex>;
|
|
41
|
+
/**
|
|
42
|
+
* The five-check anchored read. Chain state is the only authority: the signer→agent lookup, the
|
|
43
|
+
* batch root, and the lineage head all come from the contracts through `client`; the store supplies
|
|
44
|
+
* only the bytes being checked. A non-ANCHORED item can never pass — pending saves go through
|
|
45
|
+
* `verifyPendingItem` instead.
|
|
46
|
+
*/
|
|
47
|
+
export declare function verifyBatchedItem(input: {
|
|
48
|
+
item: BatchedReadItem;
|
|
49
|
+
chainId: bigint;
|
|
50
|
+
deployment: Deployment;
|
|
51
|
+
client: PublicClient;
|
|
52
|
+
requireLatest: boolean;
|
|
53
|
+
}): Promise<BatchedVerdict>;
|
|
54
|
+
/**
|
|
55
|
+
* Amendment B.2 pending read: everything checkable without anchor inclusion — bytes, signature,
|
|
56
|
+
* registered author, contextId — plus the one live check that matters most for a not-yet-anchored
|
|
57
|
+
* save: the author's current authority, chosen exactly as `BatchAnchor._checkAndApply` chooses it.
|
|
58
|
+
* A new lineage needs CREATE+INFERENCE; a replacement needs SUPERSEDE_OWN when the signer authored
|
|
59
|
+
* the lineage root, SUPERSEDE_ANY otherwise — a save queued before a revocation must not survive
|
|
60
|
+
* this. Inclusion and freshness are deliberately unchecked: the contract will run them at anchor
|
|
61
|
+
* time.
|
|
62
|
+
*/
|
|
63
|
+
export declare function verifyPendingItem(input: {
|
|
64
|
+
item: BatchedReadItem;
|
|
65
|
+
chainId: bigint;
|
|
66
|
+
deployment: Deployment;
|
|
67
|
+
client: PublicClient;
|
|
68
|
+
}): Promise<PendingVerdict>;
|