scientific-protocol 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.
Files changed (34) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +138 -0
  3. package/dist/generated/contracts.d.ts +31442 -0
  4. package/dist/generated/contracts.js +10623 -0
  5. package/dist/sdk/client.d.ts +376 -0
  6. package/dist/sdk/client.js +427 -0
  7. package/dist/sdk/index.d.ts +8 -0
  8. package/dist/sdk/index.js +7 -0
  9. package/dist/sdk/rewards.d.ts +42 -0
  10. package/dist/sdk/rewards.js +84 -0
  11. package/dist/sdk/types.d.ts +300 -0
  12. package/dist/sdk/types.js +1 -0
  13. package/dist/shared/agent-request-envelope.d.ts +40 -0
  14. package/dist/shared/agent-request-envelope.js +51 -0
  15. package/dist/shared/artifact-storage-attestations.d.ts +64 -0
  16. package/dist/shared/artifact-storage-attestations.js +104 -0
  17. package/dist/shared/artifact-storage-bundles.d.ts +44 -0
  18. package/dist/shared/artifact-storage-bundles.js +124 -0
  19. package/dist/shared/artifact-storage-policy.d.ts +38 -0
  20. package/dist/shared/artifact-storage-policy.js +47 -0
  21. package/dist/shared/contracts.d.ts +30 -0
  22. package/dist/shared/contracts.js +46 -0
  23. package/dist/shared/deployment.d.ts +52 -0
  24. package/dist/shared/deployment.js +156 -0
  25. package/dist/shared/secrets.d.ts +6 -0
  26. package/dist/shared/secrets.js +30 -0
  27. package/dist/shared/sha256.d.ts +2 -0
  28. package/dist/shared/sha256.js +4 -0
  29. package/package.json +103 -0
  30. package/schemas/artifact-storage-attestation.schema.json +116 -0
  31. package/schemas/artifact-storage-bundle.schema.json +107 -0
  32. package/schemas/claim.schema.json +83 -0
  33. package/schemas/evaluation.schema.json +96 -0
  34. package/schemas/replication.schema.json +103 -0
@@ -0,0 +1,300 @@
1
+ import type { AgentRequestEnvelope } from "../shared/agent-request-envelope.js";
2
+ export type { AgentRequestActionType, AgentRequestEnvelope, } from "../shared/agent-request-envelope.js";
3
+ export type { DeploymentAddresses, DeploymentFile } from "../shared/deployment.js";
4
+ export type ProtocolRecord = any;
5
+ export type AgentRequestView = ProtocolRecord;
6
+ export type AgentReviewCalibrationContributionView = ProtocolRecord;
7
+ export type AgentReviewCalibrationView = ProtocolRecord;
8
+ export type AgentRewardStateView = ProtocolRecord;
9
+ export type AgentRuntimeEventView = ProtocolRecord;
10
+ export type AgentView = ProtocolRecord;
11
+ export type AgentWebhookDeliveryView = ProtocolRecord;
12
+ export type AgentWebhookEventType = string;
13
+ export type AgentWebhookSubscriptionView = ProtocolRecord;
14
+ export type AgentWorkSummaryView = ProtocolRecord;
15
+ export type AppealView = ProtocolRecord;
16
+ export type ArtifactMaintenanceTaskRunView = ProtocolRecord;
17
+ export type ArtifactMaintenanceTaskView = ProtocolRecord;
18
+ export type ArtifactView = ProtocolRecord;
19
+ export type ChallengeView = ProtocolRecord;
20
+ export type CheckpointView = ProtocolRecord;
21
+ export type ClaimEventView = ProtocolRecord;
22
+ export type ClaimFeedItemView = ProtocolRecord;
23
+ export type ClaimReviewState = ProtocolRecord;
24
+ export type ClaimRewardStateView = ProtocolRecord;
25
+ export type ClaimView = ProtocolRecord;
26
+ export type ClaimWorkGraphView = ProtocolRecord;
27
+ export type ClaimWorkItemDetailView = ProtocolRecord;
28
+ export type ClaimWorkItemView = ProtocolRecord;
29
+ export type ClaimWorkOrchestrationView = ProtocolRecord;
30
+ export type ClaimWorkRoutingView = ProtocolRecord;
31
+ export type ClaimWorkSchedulingView = ProtocolRecord;
32
+ export type ConfirmSourcePublicationResult = ProtocolRecord;
33
+ export type DemoClaimInput = ProtocolRecord;
34
+ export type DemoClaimResult = ProtocolRecord;
35
+ export type DemoDomainRecomputeResult = ProtocolRecord;
36
+ export type DemoScenarioView = ProtocolRecord;
37
+ export type ForecastView = ProtocolRecord;
38
+ export type GovernanceEventView = ProtocolRecord;
39
+ export type GovernanceOverviewView = ProtocolRecord;
40
+ export type GovernanceProposalDetailView = ProtocolRecord;
41
+ export type GovernanceProposalSummaryView = ProtocolRecord;
42
+ export type GovernanceTreasuryView = ProtocolRecord;
43
+ export type IndexerRuntimeStatus = ProtocolRecord;
44
+ export type PersistedArtifactAuditView = ProtocolRecord;
45
+ export type PersistedArtifactProvenanceView = ProtocolRecord;
46
+ export type PersistedArtifactReplicaView = ProtocolRecord;
47
+ export type PersistedArtifactView = ProtocolRecord;
48
+ export type ProductionArtifactDraftInput = ProtocolRecord;
49
+ export type ProductionArtifactDraftResult = ProtocolRecord;
50
+ export type ProductionClaimInput = ProtocolRecord;
51
+ export type ProductionClaimResult = ProtocolRecord;
52
+ export type ReadModelCounts = Record<string, number>;
53
+ export type RecipientRewardStateView = ProtocolRecord;
54
+ export type RejectSourcePublicationResult = ProtocolRecord;
55
+ export type ReplicationJobRunView = ProtocolRecord;
56
+ export type ReplicationJobView = ProtocolRecord;
57
+ export type ReplicationView = ProtocolRecord;
58
+ export type ReviewAuthorResponseView = ProtocolRecord;
59
+ export type ReviewIssueView = ProtocolRecord;
60
+ export type ReviewSubmissionView = ProtocolRecord;
61
+ export type ReviewTaskRunView = ProtocolRecord;
62
+ export type ReviewTaskView = ProtocolRecord;
63
+ export type RewardProtocolConfigView = ProtocolRecord;
64
+ export type RewardSettlementHistoryView = ProtocolRecord;
65
+ export type SourceEventView = ProtocolRecord;
66
+ export type SourceExtractionCandidate = ProtocolRecord;
67
+ export type SourceFeedItemView = ProtocolRecord;
68
+ export type SourcePublicationDecisionView = ProtocolRecord;
69
+ export type SourceRecordView = ProtocolRecord;
70
+ export type SourceWorkGraphView = ProtocolRecord;
71
+ export type WriteProtocolConfigView = ProtocolRecord;
72
+ export type PublicWriteActionType = "claim_create" | "claim_draft_from_artifact" | "domain_recompute" | "replication_job_open" | "replication_job_process" | "replication_job_resolve" | "source_publication_confirm" | "source_publication_reject" | "source_submit";
73
+ export type PublicWriteEnvelope = {
74
+ actionType: PublicWriteActionType;
75
+ actorAddress: string;
76
+ chainId: number;
77
+ issuedAt: string;
78
+ payload: ProtocolRecord;
79
+ requestNonce: string;
80
+ scopeKey: string;
81
+ };
82
+ export type ReadModel = {
83
+ metadata: ProtocolRecord;
84
+ [key: string]: unknown;
85
+ };
86
+ export type PageResult<T> = {
87
+ items: T[];
88
+ limit: number;
89
+ offset: number;
90
+ total: number;
91
+ };
92
+ export type PagedResponse<T> = PageResult<T>;
93
+ export type ClaimCollectionCounts = {
94
+ appeals: number;
95
+ artifacts: number;
96
+ challenges: number;
97
+ checkpoints: number;
98
+ forecasts: number;
99
+ replications: number;
100
+ };
101
+ export type ClaimDetailResponse = ClaimView & {
102
+ collectionCounts: ClaimCollectionCounts;
103
+ appeals?: AppealView[];
104
+ artifacts?: ArtifactView[];
105
+ challenges?: ChallengeView[];
106
+ checkpoints?: CheckpointView[];
107
+ forecasts?: ForecastView[];
108
+ replications?: ReplicationView[];
109
+ rewards?: ClaimRewardStateView;
110
+ review?: ClaimReviewState;
111
+ workGraph?: ClaimWorkGraphView;
112
+ };
113
+ export type DemoScenarioPayload = DemoScenarioView & {
114
+ claim: (ClaimView & {
115
+ collectionCounts: ClaimCollectionCounts;
116
+ }) | null;
117
+ };
118
+ export type ApiSyncStatus = {
119
+ blocksRemaining: number | null;
120
+ chainHeadBlock: number | null;
121
+ cursorBlock: number | null;
122
+ indexer: IndexerRuntimeStatus;
123
+ lagBlocks: number | null;
124
+ rpcError: string | null;
125
+ rpcReachable: boolean;
126
+ syncedToHead: boolean | null;
127
+ };
128
+ export type HealthResponse = ReadModel["metadata"] & {
129
+ counts: ReadModelCounts;
130
+ databaseUrl: string;
131
+ ok: true;
132
+ sync: ApiSyncStatus;
133
+ };
134
+ export type AdminStatusResponse = {
135
+ counts: ReadModelCounts;
136
+ metadata: ReadModel["metadata"];
137
+ sync: ApiSyncStatus;
138
+ };
139
+ export type DemoAdminStatusResponse = {
140
+ counts: ReadModelCounts;
141
+ ok: true;
142
+ scenarios: DemoScenarioPayload[];
143
+ sync: ApiSyncStatus;
144
+ tokenConfigured: boolean;
145
+ };
146
+ export type DemoMutationResponse<TResult> = {
147
+ ok: true;
148
+ result: TResult;
149
+ synced?: {
150
+ indexedAt: string;
151
+ latestBlock: number;
152
+ };
153
+ };
154
+ export type DemoScenariosResponse = {
155
+ items: DemoScenarioPayload[];
156
+ };
157
+ export type ReplicationJobDetailResponse = {
158
+ artifact: PersistedArtifactDetailResponse | null;
159
+ job: ReplicationJobView | null;
160
+ runs: ReplicationJobRunView[];
161
+ };
162
+ export type ArtifactMaintenanceTaskDetailResponse = {
163
+ artifact: PersistedArtifactDetailResponse | null;
164
+ runs: ArtifactMaintenanceTaskRunView[];
165
+ task: ArtifactMaintenanceTaskView;
166
+ };
167
+ export type ReviewTaskDetailResponse = {
168
+ runs: ReviewTaskRunView[];
169
+ submissions: ReviewSubmissionView[];
170
+ task: ReviewTaskView;
171
+ };
172
+ export type SourceDetailResponse = {
173
+ candidates: SourceExtractionCandidate[];
174
+ publicationDecisions: PagedResponse<SourcePublicationDecisionView>;
175
+ source: SourceRecordView;
176
+ tasks: ReviewTaskView[];
177
+ workGraph: SourceWorkGraphView;
178
+ };
179
+ export type SourceIngestionResponse = {
180
+ ok: true;
181
+ requestId: string;
182
+ result: ProductionArtifactDraftResult;
183
+ };
184
+ export type SourceListQuery = {
185
+ limit?: number;
186
+ offset?: number;
187
+ status?: "discovered" | "snapshotted" | "extracting" | "ready_for_publication" | "published" | "rejected";
188
+ };
189
+ export type SourceListResponse = PagedResponse<SourceRecordView>;
190
+ export type SourcePublicationDecisionsResponse = PagedResponse<SourcePublicationDecisionView>;
191
+ export type SourceFeedResponse = PagedResponse<SourceFeedItemView>;
192
+ export type ClaimFeedResponse = PagedResponse<ClaimFeedItemView>;
193
+ export type SourceEventsResponse = PagedResponse<SourceEventView>;
194
+ export type ClaimEventsResponse = PagedResponse<ClaimEventView>;
195
+ export type ConfirmSourcePublicationResponse = {
196
+ ok: true;
197
+ requestId: string;
198
+ result: ConfirmSourcePublicationResult;
199
+ synced: {
200
+ indexedAt: string;
201
+ latestBlock: number;
202
+ };
203
+ };
204
+ export type RejectSourcePublicationResponse = {
205
+ ok: true;
206
+ requestId: string;
207
+ result: RejectSourcePublicationResult;
208
+ };
209
+ export type ClaimWorkGraphResponse = ClaimWorkGraphView;
210
+ export type SourceWorkGraphResponse = SourceWorkGraphView;
211
+ export type ClaimWorkItemDetailResponse = ClaimWorkItemDetailView;
212
+ export type AgentRequestDetailResponse = AgentRequestView;
213
+ export type AgentReviewCalibrationResponse = AgentReviewCalibrationView & {
214
+ contributions: PagedResponse<AgentReviewCalibrationContributionView>;
215
+ };
216
+ export type AgentWorkSummaryResponse = {
217
+ agentId: string;
218
+ domainId: number | null;
219
+ summary: AgentWorkSummaryView;
220
+ };
221
+ export type ClaimRewardStateResponse = ClaimRewardStateView;
222
+ export type AgentRewardStateResponse = AgentRewardStateView;
223
+ export type RecipientRewardStateResponse = RecipientRewardStateView;
224
+ export type RewardSettlementHistoryResponse = RewardSettlementHistoryView;
225
+ export type RewardProtocolConfigResponse = RewardProtocolConfigView;
226
+ export type WriteProtocolConfigResponse = WriteProtocolConfigView;
227
+ export type GovernanceEventsResponse = PagedResponse<GovernanceEventView>;
228
+ export type GovernanceOverviewResponse = GovernanceOverviewView;
229
+ export type GovernanceTreasuryResponse = GovernanceTreasuryView;
230
+ export type GovernanceProposalDetailResponse = GovernanceProposalDetailView;
231
+ export type GovernanceProposalsResponse = PagedResponse<GovernanceProposalSummaryView>;
232
+ export type AgentRuntimeEventsResponse = PagedResponse<AgentRuntimeEventView>;
233
+ export type AgentWebhookSubscriptionsResponse = PagedResponse<AgentWebhookSubscriptionView>;
234
+ export type AgentWebhookDeliveriesResponse = PagedResponse<AgentWebhookDeliveryView>;
235
+ export type AgentWebhookSubscriptionCreateResponse = {
236
+ ok: true;
237
+ result: {
238
+ signingSecret: string;
239
+ subscription: AgentWebhookSubscriptionView;
240
+ };
241
+ };
242
+ export type AgentWebhookSubscriptionDeleteResponse = {
243
+ ok: true;
244
+ result: AgentWebhookSubscriptionView | null;
245
+ };
246
+ export type AgentWebhookSubscriptionPingResponse = {
247
+ ok: true;
248
+ result: {
249
+ delivery: AgentWebhookDeliveryView;
250
+ subscription: AgentWebhookSubscriptionView;
251
+ };
252
+ };
253
+ export type SignedAgentRequestBody = {
254
+ envelope: AgentRequestEnvelope;
255
+ signature: string;
256
+ };
257
+ export type SignedPublicWriteRequestBody = {
258
+ envelope: PublicWriteEnvelope;
259
+ signature: string;
260
+ };
261
+ export type PersistedArtifactDetailResponse = PersistedArtifactView & {
262
+ provenance: PersistedArtifactProvenanceView | null;
263
+ recentAudits: PagedResponse<PersistedArtifactAuditView>;
264
+ replicas: PersistedArtifactReplicaView[];
265
+ };
266
+ export type DomainLeaderboardResponse<TEntry = Record<string, unknown>> = {
267
+ items: TEntry[];
268
+ latestPayload: {
269
+ computedAt: string;
270
+ domainId: number;
271
+ payloadHash: string;
272
+ payloadId: string;
273
+ uri: string;
274
+ } | null;
275
+ limit: number;
276
+ offset: number;
277
+ total: number;
278
+ };
279
+ export type ClaimListQuery = {
280
+ author?: string;
281
+ domainId?: number;
282
+ limit?: number;
283
+ offset?: number;
284
+ status?: number;
285
+ };
286
+ export type CreateDemoClaimRequest = DemoClaimInput;
287
+ export type CreateProductionClaimRequest = ProductionClaimInput;
288
+ export type CreateProductionArtifactDraftRequest = ProductionArtifactDraftInput;
289
+ export type OpenDemoReplicationJobRequest = {
290
+ claimId: string;
291
+ requestedBy?: string;
292
+ };
293
+ export type ProcessDemoReplicationJobRequest = {
294
+ workerId?: string;
295
+ };
296
+ export type ResolveDemoReplicationJobRequest = {
297
+ claimStatus?: number;
298
+ confidenceBps?: number;
299
+ resolutionStatus?: number;
300
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ export type AgentRequestActionType = "artifact_task_audit_submission" | "artifact_task_claim" | "artifact_task_heartbeat" | "artifact_task_repair_submission" | "replication_job_claim" | "replication_job_heartbeat" | "replication_job_submission" | "source_discovery_submission" | "webhook_subscription_create" | "webhook_subscription_delete" | "webhook_subscription_ping" | "review_task_heartbeat" | "review_task_claim" | "review_task_submission";
2
+ export type AgentRequestEnvelope = {
3
+ actionType: AgentRequestActionType;
4
+ actorAddress: string;
5
+ agentId: string;
6
+ issuedAt: string;
7
+ payload: Record<string, unknown>;
8
+ requestNonce: string;
9
+ scopeKey: string;
10
+ };
11
+ export declare function hashAgentRequestEnvelope(envelope: AgentRequestEnvelope): string;
12
+ export declare function verifyAgentRequestEnvelope(input: {
13
+ envelope: AgentRequestEnvelope;
14
+ signature: string;
15
+ }): {
16
+ recoveredAddress: string;
17
+ requestHash: string;
18
+ };
19
+ export type AgentRequestSigner = {
20
+ getAddress(): Promise<string>;
21
+ signMessage(message: string | Uint8Array): Promise<string>;
22
+ };
23
+ export type SignedAgentRequestEnvelope = {
24
+ envelope: AgentRequestEnvelope;
25
+ signature: string;
26
+ };
27
+ export declare function signAgentRequestEnvelope(input: {
28
+ envelope: AgentRequestEnvelope;
29
+ signer: AgentRequestSigner;
30
+ }): Promise<SignedAgentRequestEnvelope>;
31
+ export declare function createSignedAgentRequest(input: {
32
+ actionType: AgentRequestActionType;
33
+ actorAddress?: string;
34
+ agentId: string;
35
+ issuedAt?: string;
36
+ payload: Record<string, unknown>;
37
+ requestNonce: string;
38
+ scopeKey: string;
39
+ signer: AgentRequestSigner;
40
+ }): Promise<SignedAgentRequestEnvelope>;
@@ -0,0 +1,51 @@
1
+ import { getBytes, verifyMessage } from "ethers";
2
+ import { sha256Hex } from "./sha256.js";
3
+ function stableSerialize(value) {
4
+ if (Array.isArray(value)) {
5
+ return `[${value.map((item) => stableSerialize(item)).join(",")}]`;
6
+ }
7
+ if (value && typeof value === "object") {
8
+ const entries = Object.entries(value)
9
+ .sort(([left], [right]) => left.localeCompare(right))
10
+ .map(([key, entryValue]) => `${JSON.stringify(key)}:${stableSerialize(entryValue)}`);
11
+ return `{${entries.join(",")}}`;
12
+ }
13
+ if (typeof value === "bigint") {
14
+ return JSON.stringify(value.toString());
15
+ }
16
+ return JSON.stringify(value);
17
+ }
18
+ export function hashAgentRequestEnvelope(envelope) {
19
+ return `0x${sha256Hex(stableSerialize(envelope))}`;
20
+ }
21
+ export function verifyAgentRequestEnvelope(input) {
22
+ const requestHash = hashAgentRequestEnvelope(input.envelope);
23
+ const recoveredAddress = verifyMessage(getBytes(requestHash), input.signature);
24
+ if (recoveredAddress.toLowerCase() !== input.envelope.actorAddress.toLowerCase()) {
25
+ throw new Error(`agent request signature mismatch: expected ${input.envelope.actorAddress}, recovered ${recoveredAddress}`);
26
+ }
27
+ return { recoveredAddress, requestHash };
28
+ }
29
+ export async function signAgentRequestEnvelope(input) {
30
+ const requestHash = hashAgentRequestEnvelope(input.envelope);
31
+ const signature = await input.signer.signMessage(getBytes(requestHash));
32
+ return {
33
+ envelope: input.envelope,
34
+ signature,
35
+ };
36
+ }
37
+ export async function createSignedAgentRequest(input) {
38
+ const actorAddress = input.actorAddress ?? (await input.signer.getAddress());
39
+ return signAgentRequestEnvelope({
40
+ envelope: {
41
+ actionType: input.actionType,
42
+ actorAddress,
43
+ agentId: input.agentId,
44
+ issuedAt: input.issuedAt ?? new Date().toISOString(),
45
+ payload: input.payload,
46
+ requestNonce: input.requestNonce,
47
+ scopeKey: input.scopeKey,
48
+ },
49
+ signer: input.signer,
50
+ });
51
+ }
@@ -0,0 +1,64 @@
1
+ import { type Signer } from "ethers";
2
+ import type { ArtifactDurabilityClass, ArtifactStorageAttestationInput, ArtifactStorageCommitmentKind } from "./artifact-storage-policy.js";
3
+ export type ArtifactStorageAttestationActionType = "artifact_storage_attestation";
4
+ export type ArtifactStorageAttestationEnvelope = {
5
+ actionType: ArtifactStorageAttestationActionType;
6
+ artifactKey: string;
7
+ attestorAddress: string;
8
+ chainId: number;
9
+ cid: string;
10
+ commitmentKind: ArtifactStorageCommitmentKind;
11
+ evidenceRef: string | null;
12
+ issuedAt: string;
13
+ nodeId: string | null;
14
+ provider: string;
15
+ providerMetadata: Record<string, unknown>;
16
+ requestNonce: string;
17
+ retentionUntil: string | null;
18
+ retrievalUrl: string | null;
19
+ scopeKey: string;
20
+ storageClass: ArtifactDurabilityClass;
21
+ storageStartedAt: string;
22
+ };
23
+ export type ArtifactStorageAttestationSigner = Pick<Signer, "getAddress" | "signMessage">;
24
+ export type SignedArtifactStorageAttestation = {
25
+ envelope: ArtifactStorageAttestationEnvelope;
26
+ signature: string;
27
+ };
28
+ export type VerifiedArtifactStorageAttestation = {
29
+ recoveredAddress: string;
30
+ signedPayloadHash: string;
31
+ };
32
+ export declare function buildArtifactStorageAttestationScopeKey(input: {
33
+ artifactKey: string;
34
+ cid: string;
35
+ }): string;
36
+ export declare function buildArtifactStorageAttestationEnvelope(input: {
37
+ artifactKey: string;
38
+ attestorAddress: string;
39
+ chainId: number;
40
+ cid: string;
41
+ commitmentKind: ArtifactStorageCommitmentKind;
42
+ evidenceRef?: string | null;
43
+ issuedAt?: string;
44
+ nodeId?: string | null;
45
+ provider: string;
46
+ providerMetadata?: Record<string, unknown>;
47
+ requestNonce: string;
48
+ retentionUntil?: string | null;
49
+ retrievalUrl?: string | null;
50
+ scopeKey?: string;
51
+ storageClass: ArtifactDurabilityClass;
52
+ storageStartedAt?: string;
53
+ }): ArtifactStorageAttestationEnvelope;
54
+ export declare function hashArtifactStorageAttestationEnvelope(envelope: ArtifactStorageAttestationEnvelope): string;
55
+ export declare function signArtifactStorageAttestation(input: {
56
+ envelope: ArtifactStorageAttestationEnvelope;
57
+ signer: ArtifactStorageAttestationSigner;
58
+ }): Promise<SignedArtifactStorageAttestation>;
59
+ export declare function createSignedArtifactStorageAttestation(input: Omit<Parameters<typeof buildArtifactStorageAttestationEnvelope>[0], "attestorAddress"> & {
60
+ attestorAddress?: string;
61
+ signer: ArtifactStorageAttestationSigner;
62
+ }): Promise<SignedArtifactStorageAttestation>;
63
+ export declare function verifyArtifactStorageAttestation(signed: SignedArtifactStorageAttestation): VerifiedArtifactStorageAttestation;
64
+ export declare function toArtifactStorageAttestationRecordInput(signed: SignedArtifactStorageAttestation): ArtifactStorageAttestationInput;
@@ -0,0 +1,104 @@
1
+ import { getBytes, verifyMessage } from "ethers";
2
+ import { sha256Hex } from "./sha256.js";
3
+ function stableSerialize(value) {
4
+ if (Array.isArray(value)) {
5
+ return `[${value.map((item) => stableSerialize(item)).join(",")}]`;
6
+ }
7
+ if (value && typeof value === "object") {
8
+ const entries = Object.entries(value)
9
+ .sort(([left], [right]) => left.localeCompare(right))
10
+ .map(([key, entryValue]) => `${JSON.stringify(key)}:${stableSerialize(entryValue)}`);
11
+ return `{${entries.join(",")}}`;
12
+ }
13
+ if (typeof value === "bigint") {
14
+ return JSON.stringify(value.toString());
15
+ }
16
+ return JSON.stringify(value);
17
+ }
18
+ function normalizeRequiredText(value, fieldName) {
19
+ const trimmed = value.trim();
20
+ if (!trimmed) {
21
+ throw new Error(`${fieldName} is required`);
22
+ }
23
+ return trimmed;
24
+ }
25
+ function normalizeOptionalText(value) {
26
+ const trimmed = value?.trim();
27
+ return trimmed ? trimmed : null;
28
+ }
29
+ export function buildArtifactStorageAttestationScopeKey(input) {
30
+ return `artifact:${normalizeRequiredText(input.artifactKey, "artifactKey")}:cid:${normalizeRequiredText(input.cid, "cid")}`;
31
+ }
32
+ export function buildArtifactStorageAttestationEnvelope(input) {
33
+ if (!Number.isSafeInteger(input.chainId) || input.chainId <= 0) {
34
+ throw new Error("chainId must be a positive safe integer");
35
+ }
36
+ const artifactKey = normalizeRequiredText(input.artifactKey, "artifactKey");
37
+ const cid = normalizeRequiredText(input.cid, "cid");
38
+ return {
39
+ actionType: "artifact_storage_attestation",
40
+ artifactKey,
41
+ attestorAddress: normalizeRequiredText(input.attestorAddress, "attestorAddress"),
42
+ chainId: input.chainId,
43
+ cid,
44
+ commitmentKind: input.commitmentKind,
45
+ evidenceRef: normalizeOptionalText(input.evidenceRef),
46
+ issuedAt: input.issuedAt ?? new Date().toISOString(),
47
+ nodeId: normalizeOptionalText(input.nodeId),
48
+ provider: normalizeRequiredText(input.provider, "provider"),
49
+ providerMetadata: input.providerMetadata ?? {},
50
+ requestNonce: normalizeRequiredText(input.requestNonce, "requestNonce"),
51
+ retentionUntil: normalizeOptionalText(input.retentionUntil),
52
+ retrievalUrl: normalizeOptionalText(input.retrievalUrl),
53
+ scopeKey: input.scopeKey ?? buildArtifactStorageAttestationScopeKey({ artifactKey, cid }),
54
+ storageClass: input.storageClass,
55
+ storageStartedAt: input.storageStartedAt ?? new Date().toISOString(),
56
+ };
57
+ }
58
+ export function hashArtifactStorageAttestationEnvelope(envelope) {
59
+ return `0x${sha256Hex(stableSerialize(envelope))}`;
60
+ }
61
+ export async function signArtifactStorageAttestation(input) {
62
+ const signedPayloadHash = hashArtifactStorageAttestationEnvelope(input.envelope);
63
+ const signature = await input.signer.signMessage(getBytes(signedPayloadHash));
64
+ return {
65
+ envelope: input.envelope,
66
+ signature,
67
+ };
68
+ }
69
+ export async function createSignedArtifactStorageAttestation(input) {
70
+ const attestorAddress = input.attestorAddress ?? (await input.signer.getAddress());
71
+ return signArtifactStorageAttestation({
72
+ envelope: buildArtifactStorageAttestationEnvelope({
73
+ ...input,
74
+ attestorAddress,
75
+ }),
76
+ signer: input.signer,
77
+ });
78
+ }
79
+ export function verifyArtifactStorageAttestation(signed) {
80
+ const signedPayloadHash = hashArtifactStorageAttestationEnvelope(signed.envelope);
81
+ const recoveredAddress = verifyMessage(getBytes(signedPayloadHash), signed.signature);
82
+ if (recoveredAddress.toLowerCase() !== signed.envelope.attestorAddress.toLowerCase()) {
83
+ throw new Error(`artifact storage attestation signature mismatch: expected ${signed.envelope.attestorAddress}, recovered ${recoveredAddress}`);
84
+ }
85
+ return { recoveredAddress, signedPayloadHash };
86
+ }
87
+ export function toArtifactStorageAttestationRecordInput(signed) {
88
+ const { signedPayloadHash } = verifyArtifactStorageAttestation(signed);
89
+ return {
90
+ attestorAddress: signed.envelope.attestorAddress,
91
+ cid: signed.envelope.cid,
92
+ commitmentKind: signed.envelope.commitmentKind,
93
+ evidenceRef: signed.envelope.evidenceRef,
94
+ nodeId: signed.envelope.nodeId,
95
+ provider: signed.envelope.provider,
96
+ providerMetadata: signed.envelope.providerMetadata,
97
+ retentionUntil: signed.envelope.retentionUntil,
98
+ retrievalUrl: signed.envelope.retrievalUrl,
99
+ signature: signed.signature,
100
+ signedPayloadHash,
101
+ storageClass: signed.envelope.storageClass,
102
+ storageStartedAt: signed.envelope.storageStartedAt,
103
+ };
104
+ }
@@ -0,0 +1,44 @@
1
+ import type { ArtifactDurabilityClass, ArtifactStoragePolicyInput } from "./artifact-storage-policy.js";
2
+ export type ArtifactStorageBundleManifestArtifactInput = {
3
+ artifactKey: string;
4
+ byteLength: number;
5
+ cid: string;
6
+ contentType: string;
7
+ durabilityClass: ArtifactDurabilityClass;
8
+ memberPath: string;
9
+ metadata?: Record<string, unknown>;
10
+ sha256: string;
11
+ sourceUri?: string | null;
12
+ };
13
+ export type ArtifactStorageBundleManifestInput = {
14
+ artifacts: ArtifactStorageBundleManifestArtifactInput[];
15
+ bundleCid?: string | null;
16
+ bundleKey: string;
17
+ bundleUri?: string | null;
18
+ generatedAt?: string;
19
+ metadata?: Record<string, unknown>;
20
+ storageRail: string;
21
+ };
22
+ export type ArtifactStorageBundleManifestArtifact = Required<Omit<ArtifactStorageBundleManifestArtifactInput, "metadata" | "sourceUri">> & {
23
+ metadata: Record<string, unknown>;
24
+ sourceUri: string | null;
25
+ };
26
+ export type ArtifactStorageBundleManifest = {
27
+ artifacts: ArtifactStorageBundleManifestArtifact[];
28
+ bundleCid: string | null;
29
+ bundleKey: string;
30
+ bundleUri: string | null;
31
+ generatedAt: string;
32
+ kind: "scientific.artifact-storage-bundle";
33
+ manifestDigest: string;
34
+ metadata: Record<string, unknown>;
35
+ storageRail: string;
36
+ version: 1;
37
+ };
38
+ export type ArtifactStorageBundlePolicyInput = {
39
+ artifactKey: string;
40
+ policy: Pick<ArtifactStoragePolicyInput, "bundleCid" | "bundleMemberPath" | "durabilityClass" | "metadata">;
41
+ };
42
+ export declare function buildArtifactStorageBundleManifest(input: ArtifactStorageBundleManifestInput): ArtifactStorageBundleManifest;
43
+ export declare function verifyArtifactStorageBundleManifest(manifest: ArtifactStorageBundleManifest): string;
44
+ export declare function createArtifactStorageBundlePolicyInputs(manifest: ArtifactStorageBundleManifest): ArtifactStorageBundlePolicyInput[];