@vallum/marketplace 0.0.0-prerelease
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/index.d.ts +132 -0
- package/dist/index.js +386 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @vallum/marketplace
|
|
2
|
+
|
|
3
|
+
Read-only local marketplace evidence views for Vallum.
|
|
4
|
+
|
|
5
|
+
This package helps a future marketplace consume existing Vallum truth:
|
|
6
|
+
registry profiles, policy compatibility, contract template metadata, receipts,
|
|
7
|
+
manifests, and standards bridge evidence. It does not operate a marketplace,
|
|
8
|
+
onboard providers, settle payments, custody funds, verify providers, moderate
|
|
9
|
+
listings, or contact live IOTA/x402/AP2/A2A services.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { type ContractTemplateMetadata, type ContractTemplateRegistry } from "@vallum/contracts-metadata";
|
|
2
|
+
import { type AgentTransactionManifest } from "@vallum/manifest";
|
|
3
|
+
import { type AgentCapabilityPolicyDecision, type AgentCapabilityRequirement } from "@vallum/policy-gateway";
|
|
4
|
+
import { type DataLicenseReceipt, type EscrowReceipt, type PayPerCallReceipt, type ReputationReceipt, type ServiceBountyReceipt, type SubscriptionReceipt } from "@vallum/receipts";
|
|
5
|
+
import { type AgentProfileStatus } from "@vallum/registry";
|
|
6
|
+
export type MarketplaceEvidenceLevel = "mock" | "local" | "testnet" | "live";
|
|
7
|
+
export type MarketplaceProfileLabel = AgentProfileStatus | "unverified";
|
|
8
|
+
export type MarketplaceRole = "buyer" | "provider" | "operator" | "reviewer";
|
|
9
|
+
export type MarketplaceReceipt = EscrowReceipt | PayPerCallReceipt | DataLicenseReceipt | ServiceBountyReceipt | ReputationReceipt | SubscriptionReceipt;
|
|
10
|
+
export interface MarketplaceViewer {
|
|
11
|
+
readonly principalId: string;
|
|
12
|
+
readonly role: MarketplaceRole;
|
|
13
|
+
}
|
|
14
|
+
export interface MarketplaceStandardsEvidence {
|
|
15
|
+
readonly protocol: "x402" | "ap2" | "a2a";
|
|
16
|
+
readonly status: MarketplaceEvidenceLevel;
|
|
17
|
+
readonly referenceId: string;
|
|
18
|
+
readonly metadata?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface MarketplaceProviderListingInput {
|
|
21
|
+
readonly providerId: string;
|
|
22
|
+
readonly profile: unknown;
|
|
23
|
+
readonly capabilityRequirement: AgentCapabilityRequirement;
|
|
24
|
+
readonly contractRegistry: ContractTemplateRegistry;
|
|
25
|
+
readonly evidenceLevel?: MarketplaceEvidenceLevel;
|
|
26
|
+
readonly standardsEvidence?: readonly MarketplaceStandardsEvidence[];
|
|
27
|
+
readonly now?: Date;
|
|
28
|
+
}
|
|
29
|
+
export interface MarketplaceProviderListing {
|
|
30
|
+
readonly providerId: string;
|
|
31
|
+
readonly displayName: string;
|
|
32
|
+
readonly profileLabel: MarketplaceProfileLabel;
|
|
33
|
+
readonly providerVerification: "unverified";
|
|
34
|
+
readonly verificationLabel: MarketplaceEvidenceLevel | "unverified";
|
|
35
|
+
readonly capabilityIds: readonly string[];
|
|
36
|
+
readonly endpointTypes: readonly string[];
|
|
37
|
+
readonly policyCompatibility: AgentCapabilityPolicyDecision;
|
|
38
|
+
readonly supportedTemplates: readonly Pick<ContractTemplateMetadata, "templateId" | "version" | "module" | "entryFunctions" | "riskCategory" | "refundDisputeBehavior">[];
|
|
39
|
+
readonly standardsEvidence: readonly Omit<MarketplaceStandardsEvidence, "metadata">[];
|
|
40
|
+
}
|
|
41
|
+
export type MarketplaceReceiptViewResult = {
|
|
42
|
+
readonly allowed: true;
|
|
43
|
+
readonly view: MarketplaceReceiptView;
|
|
44
|
+
} | {
|
|
45
|
+
readonly allowed: false;
|
|
46
|
+
readonly reasonCode: "MARKETPLACE_RECEIPT_ACCESS_DENIED";
|
|
47
|
+
readonly message: string;
|
|
48
|
+
};
|
|
49
|
+
export interface MarketplaceReceiptView {
|
|
50
|
+
readonly receiptId: string;
|
|
51
|
+
readonly manifestId: string;
|
|
52
|
+
readonly status: MarketplaceReceipt["status"];
|
|
53
|
+
readonly workflow: MarketplaceWorkflow;
|
|
54
|
+
readonly parties: {
|
|
55
|
+
readonly agentId: string;
|
|
56
|
+
readonly ownerId: string;
|
|
57
|
+
readonly providerId?: string;
|
|
58
|
+
readonly requesterId?: string;
|
|
59
|
+
readonly licenseeId?: string;
|
|
60
|
+
readonly subscriberId?: string;
|
|
61
|
+
readonly issuerId?: string;
|
|
62
|
+
readonly subjectId?: string;
|
|
63
|
+
};
|
|
64
|
+
readonly amount: MarketplaceReceipt["amount"];
|
|
65
|
+
readonly transactionDigest?: string;
|
|
66
|
+
readonly sponsorshipId?: string;
|
|
67
|
+
readonly events: readonly {
|
|
68
|
+
readonly type: string;
|
|
69
|
+
readonly at: string;
|
|
70
|
+
readonly reason?: string;
|
|
71
|
+
}[];
|
|
72
|
+
}
|
|
73
|
+
export interface CreateMarketplaceReceiptViewInput {
|
|
74
|
+
readonly receipt: MarketplaceReceipt;
|
|
75
|
+
readonly viewer: MarketplaceViewer;
|
|
76
|
+
}
|
|
77
|
+
export interface CreateDisputeEvidenceBundleInput {
|
|
78
|
+
readonly receipt: MarketplaceReceipt;
|
|
79
|
+
readonly manifest: AgentTransactionManifest;
|
|
80
|
+
readonly template?: ContractTemplateMetadata;
|
|
81
|
+
readonly standardsEvidence?: readonly MarketplaceStandardsEvidence[];
|
|
82
|
+
readonly viewer: MarketplaceViewer;
|
|
83
|
+
}
|
|
84
|
+
export interface MarketplaceDisputeEvidenceBundle {
|
|
85
|
+
readonly bundleHash: string;
|
|
86
|
+
readonly visibility: "party" | "operator" | "reviewer";
|
|
87
|
+
readonly links: {
|
|
88
|
+
readonly manifestId: string;
|
|
89
|
+
readonly receiptId: string;
|
|
90
|
+
readonly templateId?: string;
|
|
91
|
+
readonly templateVersion?: string;
|
|
92
|
+
readonly transactionDigest?: string;
|
|
93
|
+
readonly standardsEvidence: readonly Omit<MarketplaceStandardsEvidence, "metadata">[];
|
|
94
|
+
};
|
|
95
|
+
readonly manifest: {
|
|
96
|
+
readonly agentId: string;
|
|
97
|
+
readonly ownerId: string;
|
|
98
|
+
readonly counterpartyId: string;
|
|
99
|
+
readonly action: {
|
|
100
|
+
readonly packageId: string;
|
|
101
|
+
readonly module?: string;
|
|
102
|
+
readonly functionName: string;
|
|
103
|
+
readonly templateId?: string;
|
|
104
|
+
readonly templateVersion?: string;
|
|
105
|
+
};
|
|
106
|
+
readonly scope: readonly string[];
|
|
107
|
+
readonly simulationRequired: boolean;
|
|
108
|
+
readonly receiptRequired: boolean;
|
|
109
|
+
};
|
|
110
|
+
readonly receipt: MarketplaceReceiptView;
|
|
111
|
+
readonly template?: Pick<ContractTemplateMetadata, "templateId" | "version" | "module" | "entryFunctions" | "riskCategory" | "refundDisputeBehavior">;
|
|
112
|
+
}
|
|
113
|
+
export interface MarketplaceReadModelDemoResult {
|
|
114
|
+
readonly providerProfileLabel: MarketplaceProfileLabel;
|
|
115
|
+
readonly policyAllowed: boolean;
|
|
116
|
+
readonly buyerReceiptAllowed: boolean;
|
|
117
|
+
readonly strangerReceiptAllowed: boolean;
|
|
118
|
+
readonly disputeBundleHash: string;
|
|
119
|
+
readonly logLeaksSecretMaterial: boolean;
|
|
120
|
+
}
|
|
121
|
+
type MarketplaceWorkflow = "escrow" | "pay_per_call" | "data_license" | "service_bounty" | "reputation_receipt" | "subscription";
|
|
122
|
+
export declare function createMarketplaceProviderListing(input: MarketplaceProviderListingInput): MarketplaceProviderListing;
|
|
123
|
+
export declare function createMarketplaceReceiptView(input: CreateMarketplaceReceiptViewInput): MarketplaceReceiptViewResult;
|
|
124
|
+
export declare function createDisputeEvidenceBundle(input: CreateDisputeEvidenceBundleInput): MarketplaceDisputeEvidenceBundle;
|
|
125
|
+
export declare function runMarketplaceReadModelDemo(): MarketplaceReadModelDemoResult;
|
|
126
|
+
export declare function formatMarketplaceReadModelDemoResult(result: MarketplaceReadModelDemoResult): string;
|
|
127
|
+
export declare class MarketplaceAccessError extends Error {
|
|
128
|
+
readonly code: "MARKETPLACE_RECEIPT_ACCESS_DENIED";
|
|
129
|
+
constructor(code: "MARKETPLACE_RECEIPT_ACCESS_DENIED", message: string);
|
|
130
|
+
}
|
|
131
|
+
export declare function redactMarketplaceEvidence(value: unknown): unknown;
|
|
132
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { defaultContractTemplateRegistry, } from "@vallum/contracts-metadata";
|
|
3
|
+
import { validManifestFixture } from "@vallum/manifest";
|
|
4
|
+
import { evaluateProfileCapabilityPolicy, } from "@vallum/policy-gateway";
|
|
5
|
+
import { approveServiceBountyReceipt, completeServiceBountyReceipt, createServiceBountyReceipt, releaseServiceBountyReceipt, sponsorServiceBountyReceipt, submitServiceBountyReceipt, } from "@vallum/receipts";
|
|
6
|
+
import { validateAgentProfile, validAgentProfileFixture, } from "@vallum/registry";
|
|
7
|
+
export function createMarketplaceProviderListing(input) {
|
|
8
|
+
const validation = validateAgentProfile(input.profile, { now: input.now });
|
|
9
|
+
const profile = validation.ok ? validation.profile : undefined;
|
|
10
|
+
const profileLabel = validation.ok ? validation.profile.status : validation.status ?? "unverified";
|
|
11
|
+
const policyCompatibility = validation.ok
|
|
12
|
+
? evaluateProfileCapabilityPolicy(profile, input.capabilityRequirement, { now: input.now })
|
|
13
|
+
: {
|
|
14
|
+
allowed: false,
|
|
15
|
+
reasonCode: "PROFILE_INVALID",
|
|
16
|
+
message: "Agent profile failed validation.",
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
providerId: input.providerId,
|
|
20
|
+
displayName: profile?.name ?? input.providerId,
|
|
21
|
+
profileLabel,
|
|
22
|
+
providerVerification: "unverified",
|
|
23
|
+
verificationLabel: validation.ok ? input.evidenceLevel ?? "mock" : "unverified",
|
|
24
|
+
capabilityIds: profile?.capabilities.map((capability) => capability.id) ?? [],
|
|
25
|
+
endpointTypes: profile?.endpoints.map((endpoint) => endpoint.type) ?? [],
|
|
26
|
+
policyCompatibility,
|
|
27
|
+
supportedTemplates: supportedTemplates(profile, input.contractRegistry),
|
|
28
|
+
standardsEvidence: (input.standardsEvidence ?? []).map(stripStandardsMetadata),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function createMarketplaceReceiptView(input) {
|
|
32
|
+
if (!canViewReceipt(input.viewer, input.receipt)) {
|
|
33
|
+
return {
|
|
34
|
+
allowed: false,
|
|
35
|
+
reasonCode: "MARKETPLACE_RECEIPT_ACCESS_DENIED",
|
|
36
|
+
message: "Marketplace receipt is not visible to this viewer.",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
allowed: true,
|
|
41
|
+
view: receiptView(input.receipt),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function createDisputeEvidenceBundle(input) {
|
|
45
|
+
const receipt = createMarketplaceReceiptView({
|
|
46
|
+
receipt: input.receipt,
|
|
47
|
+
viewer: input.viewer,
|
|
48
|
+
});
|
|
49
|
+
if (!receipt.allowed) {
|
|
50
|
+
throw new MarketplaceAccessError(receipt.reasonCode, receipt.message);
|
|
51
|
+
}
|
|
52
|
+
const bundleWithoutHash = {
|
|
53
|
+
visibility: visibility(input.viewer),
|
|
54
|
+
links: {
|
|
55
|
+
manifestId: input.receipt.manifestId,
|
|
56
|
+
receiptId: input.receipt.receiptId,
|
|
57
|
+
...(input.template ? {
|
|
58
|
+
templateId: input.template.templateId,
|
|
59
|
+
templateVersion: input.template.version,
|
|
60
|
+
} : {}),
|
|
61
|
+
...("transactionDigest" in input.receipt && input.receipt.transactionDigest
|
|
62
|
+
? { transactionDigest: input.receipt.transactionDigest }
|
|
63
|
+
: {}),
|
|
64
|
+
standardsEvidence: (input.standardsEvidence ?? []).map(stripStandardsMetadata),
|
|
65
|
+
},
|
|
66
|
+
manifest: {
|
|
67
|
+
agentId: input.manifest.agent.id,
|
|
68
|
+
ownerId: input.manifest.owner.id,
|
|
69
|
+
counterpartyId: input.manifest.counterparty.id,
|
|
70
|
+
action: {
|
|
71
|
+
packageId: input.manifest.action.packageId,
|
|
72
|
+
...(input.manifest.action.module ? { module: input.manifest.action.module } : {}),
|
|
73
|
+
functionName: input.manifest.action.functionName,
|
|
74
|
+
...(input.manifest.action.templateId ? { templateId: input.manifest.action.templateId } : {}),
|
|
75
|
+
...(input.manifest.action.templateVersion ? { templateVersion: input.manifest.action.templateVersion } : {}),
|
|
76
|
+
},
|
|
77
|
+
scope: input.manifest.scope,
|
|
78
|
+
simulationRequired: input.manifest.simulation.required,
|
|
79
|
+
receiptRequired: input.manifest.receipt.required,
|
|
80
|
+
},
|
|
81
|
+
receipt: receipt.view,
|
|
82
|
+
...(input.template ? { template: templateSummary(input.template) } : {}),
|
|
83
|
+
};
|
|
84
|
+
const redacted = redactMarketplaceEvidence(bundleWithoutHash);
|
|
85
|
+
return {
|
|
86
|
+
bundleHash: `sha256:${sha256(stableStringify(redacted))}`,
|
|
87
|
+
...redacted,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export function runMarketplaceReadModelDemo() {
|
|
91
|
+
const now = new Date("2026-06-10T12:00:00.000Z");
|
|
92
|
+
const receipt = appendMarketplaceDiagnosticEvent(createReleasedServiceBountyReceipt({
|
|
93
|
+
receiptId: "receipt_marketplace_demo_1",
|
|
94
|
+
manifestId: "manifest_marketplace_demo_1",
|
|
95
|
+
idempotencyKey: "idem_marketplace_demo_1",
|
|
96
|
+
agentId: "agent:quote-bot",
|
|
97
|
+
ownerId: "owner:alice",
|
|
98
|
+
requesterId: "owner:alice",
|
|
99
|
+
providerId: "provider:quote-service",
|
|
100
|
+
bountyId: "bounty:demo",
|
|
101
|
+
deliverableHash: "sha256:deliverable",
|
|
102
|
+
amount: { amount: "10.00", asset: "USD" },
|
|
103
|
+
transactionDigest: "digest_marketplace_demo",
|
|
104
|
+
sponsorshipId: "mock_sponsorship_marketplace",
|
|
105
|
+
now,
|
|
106
|
+
}), now);
|
|
107
|
+
const listing = createMarketplaceProviderListing({
|
|
108
|
+
providerId: "provider:quote-service",
|
|
109
|
+
profile: {
|
|
110
|
+
...validProfile(),
|
|
111
|
+
capabilities: [{
|
|
112
|
+
id: "research.summary",
|
|
113
|
+
contracts: ["escrow:v1"],
|
|
114
|
+
scopes: ["contract:escrow"],
|
|
115
|
+
}],
|
|
116
|
+
},
|
|
117
|
+
capabilityRequirement: {
|
|
118
|
+
capabilityId: "research.summary",
|
|
119
|
+
scope: "contract:escrow",
|
|
120
|
+
contract: "escrow:v1",
|
|
121
|
+
},
|
|
122
|
+
contractRegistry: defaultContractTemplateRegistry,
|
|
123
|
+
evidenceLevel: "local",
|
|
124
|
+
standardsEvidence: [{ protocol: "a2a", status: "local", referenceId: "a2a-local-server-smoke" }],
|
|
125
|
+
now,
|
|
126
|
+
});
|
|
127
|
+
const buyer = createMarketplaceReceiptView({
|
|
128
|
+
receipt,
|
|
129
|
+
viewer: { principalId: "owner:alice", role: "buyer" },
|
|
130
|
+
});
|
|
131
|
+
const stranger = createMarketplaceReceiptView({
|
|
132
|
+
receipt,
|
|
133
|
+
viewer: { principalId: "agent:unrelated", role: "buyer" },
|
|
134
|
+
});
|
|
135
|
+
const bundle = createDisputeEvidenceBundle({
|
|
136
|
+
receipt,
|
|
137
|
+
manifest: {
|
|
138
|
+
...validManifestFixture(),
|
|
139
|
+
intent: "Use private prompt with Bearer abc.def.ghi",
|
|
140
|
+
},
|
|
141
|
+
template: defaultContractTemplateRegistry.findTemplate("service_bounty_v1", "1.0.0"),
|
|
142
|
+
standardsEvidence: [{ protocol: "a2a", status: "local", referenceId: "a2a-local-server-smoke" }],
|
|
143
|
+
viewer: { principalId: "operator:demo", role: "operator" },
|
|
144
|
+
});
|
|
145
|
+
const serialized = JSON.stringify({ listing, buyer, stranger, bundle });
|
|
146
|
+
return {
|
|
147
|
+
providerProfileLabel: listing.profileLabel,
|
|
148
|
+
policyAllowed: listing.policyCompatibility.allowed,
|
|
149
|
+
buyerReceiptAllowed: buyer.allowed,
|
|
150
|
+
strangerReceiptAllowed: stranger.allowed,
|
|
151
|
+
disputeBundleHash: bundle.bundleHash,
|
|
152
|
+
logLeaksSecretMaterial: responseLeaks(serialized),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
export function formatMarketplaceReadModelDemoResult(result) {
|
|
156
|
+
return [
|
|
157
|
+
"Marketplace read-model demo passed",
|
|
158
|
+
`provider.profileLabel=${result.providerProfileLabel}`,
|
|
159
|
+
`policy.allowed=${result.policyAllowed}`,
|
|
160
|
+
`buyerReceipt.allowed=${result.buyerReceiptAllowed}`,
|
|
161
|
+
`strangerReceipt.allowed=${result.strangerReceiptAllowed}`,
|
|
162
|
+
`dispute.bundleHash=${result.disputeBundleHash}`,
|
|
163
|
+
`logLeaksSecretMaterial=${result.logLeaksSecretMaterial}`,
|
|
164
|
+
].join("\n");
|
|
165
|
+
}
|
|
166
|
+
export class MarketplaceAccessError extends Error {
|
|
167
|
+
code;
|
|
168
|
+
constructor(code, message) {
|
|
169
|
+
super(message);
|
|
170
|
+
this.code = code;
|
|
171
|
+
this.name = "MarketplaceAccessError";
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
export function redactMarketplaceEvidence(value) {
|
|
175
|
+
if (Array.isArray(value))
|
|
176
|
+
return value.map(redactMarketplaceEvidence);
|
|
177
|
+
if (!isRecord(value))
|
|
178
|
+
return typeof value === "string" ? redactString(value) : value;
|
|
179
|
+
const redacted = {};
|
|
180
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
181
|
+
if (isSecretKey(key)) {
|
|
182
|
+
redacted[key] = "[REDACTED]";
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
redacted[key] = redactMarketplaceEvidence(nested);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return redacted;
|
|
189
|
+
}
|
|
190
|
+
function receiptView(receipt) {
|
|
191
|
+
const record = receipt;
|
|
192
|
+
return redactMarketplaceEvidence({
|
|
193
|
+
receiptId: receipt.receiptId,
|
|
194
|
+
manifestId: receipt.manifestId,
|
|
195
|
+
status: receipt.status,
|
|
196
|
+
workflow: workflow(receipt),
|
|
197
|
+
parties: {
|
|
198
|
+
agentId: receipt.agentId,
|
|
199
|
+
ownerId: receipt.ownerId,
|
|
200
|
+
...pickString(record, "providerId"),
|
|
201
|
+
...pickString(record, "requesterId"),
|
|
202
|
+
...pickString(record, "licenseeId"),
|
|
203
|
+
...pickString(record, "subscriberId"),
|
|
204
|
+
...pickString(record, "issuerId"),
|
|
205
|
+
...pickString(record, "subjectId"),
|
|
206
|
+
},
|
|
207
|
+
amount: receipt.amount,
|
|
208
|
+
...("transactionDigest" in receipt && receipt.transactionDigest
|
|
209
|
+
? { transactionDigest: receipt.transactionDigest }
|
|
210
|
+
: {}),
|
|
211
|
+
...("sponsorshipId" in receipt && receipt.sponsorshipId ? { sponsorshipId: receipt.sponsorshipId } : {}),
|
|
212
|
+
events: receipt.events.map((event) => ({
|
|
213
|
+
type: event.type,
|
|
214
|
+
at: event.at,
|
|
215
|
+
...(event.reason ? { reason: event.reason } : {}),
|
|
216
|
+
})),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function canViewReceipt(viewer, receipt) {
|
|
220
|
+
if (viewer.role === "operator" || viewer.role === "reviewer")
|
|
221
|
+
return true;
|
|
222
|
+
const parties = partyIds(receipt);
|
|
223
|
+
if (viewer.role === "provider")
|
|
224
|
+
return parties.providers.includes(viewer.principalId);
|
|
225
|
+
return parties.buyers.includes(viewer.principalId);
|
|
226
|
+
}
|
|
227
|
+
function partyIds(receipt) {
|
|
228
|
+
const record = receipt;
|
|
229
|
+
const buyers = [
|
|
230
|
+
receipt.agentId,
|
|
231
|
+
receipt.ownerId,
|
|
232
|
+
stringValue(record.requesterId),
|
|
233
|
+
stringValue(record.licenseeId),
|
|
234
|
+
stringValue(record.subscriberId),
|
|
235
|
+
stringValue(record.issuerId),
|
|
236
|
+
].filter(isString);
|
|
237
|
+
const providers = [
|
|
238
|
+
stringValue(record.providerId),
|
|
239
|
+
stringValue(record.subjectId),
|
|
240
|
+
isEscrowReceipt(receipt) ? receipt.escrow.providerId : undefined,
|
|
241
|
+
isEscrowReceipt(receipt) ? receipt.escrow.verifierId : undefined,
|
|
242
|
+
].filter(isString);
|
|
243
|
+
return { buyers, providers };
|
|
244
|
+
}
|
|
245
|
+
function workflow(receipt) {
|
|
246
|
+
if ("toolName" in receipt)
|
|
247
|
+
return "pay_per_call";
|
|
248
|
+
if ("datasetId" in receipt)
|
|
249
|
+
return "data_license";
|
|
250
|
+
if ("bountyId" in receipt)
|
|
251
|
+
return "service_bounty";
|
|
252
|
+
if ("interactionId" in receipt)
|
|
253
|
+
return "reputation_receipt";
|
|
254
|
+
if ("planId" in receipt)
|
|
255
|
+
return "subscription";
|
|
256
|
+
return "escrow";
|
|
257
|
+
}
|
|
258
|
+
function createReleasedServiceBountyReceipt(input) {
|
|
259
|
+
const approved = approveServiceBountyReceipt(createServiceBountyReceipt({
|
|
260
|
+
receiptId: input.receiptId,
|
|
261
|
+
manifestId: input.manifestId,
|
|
262
|
+
idempotencyKey: input.idempotencyKey,
|
|
263
|
+
agentId: input.agentId,
|
|
264
|
+
ownerId: input.ownerId,
|
|
265
|
+
requesterId: input.requesterId,
|
|
266
|
+
providerId: input.providerId,
|
|
267
|
+
bountyId: input.bountyId,
|
|
268
|
+
deliverableHash: input.deliverableHash,
|
|
269
|
+
amount: input.amount,
|
|
270
|
+
createdAt: input.now,
|
|
271
|
+
}), { at: input.now });
|
|
272
|
+
const sponsored = sponsorServiceBountyReceipt(approved, {
|
|
273
|
+
at: input.now,
|
|
274
|
+
sponsorshipId: input.sponsorshipId,
|
|
275
|
+
});
|
|
276
|
+
const submitted = submitServiceBountyReceipt(sponsored, {
|
|
277
|
+
at: input.now,
|
|
278
|
+
transactionDigest: input.transactionDigest,
|
|
279
|
+
});
|
|
280
|
+
const completed = completeServiceBountyReceipt(submitted, {
|
|
281
|
+
at: input.now,
|
|
282
|
+
completionProofHash: "sha256:completion",
|
|
283
|
+
});
|
|
284
|
+
return releaseServiceBountyReceipt(completed, {
|
|
285
|
+
at: input.now,
|
|
286
|
+
releaseProofHash: "sha256:release",
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function appendMarketplaceDiagnosticEvent(receipt, at) {
|
|
290
|
+
return {
|
|
291
|
+
...receipt,
|
|
292
|
+
events: [
|
|
293
|
+
...receipt.events,
|
|
294
|
+
{ type: "sponsored", at: at.toISOString(), reason: "private prompt Bearer abc.def.ghi" },
|
|
295
|
+
],
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function supportedTemplates(profile, registry) {
|
|
299
|
+
const supported = new Set(profile?.supportedContracts?.map((contract) => contract.id) ?? []);
|
|
300
|
+
const allTemplates = registry.templates.map(templateSummary);
|
|
301
|
+
if (supported.size === 0)
|
|
302
|
+
return allTemplates;
|
|
303
|
+
return allTemplates.filter((template) => supported.has(template.templateId) || supported.has(templateIdAlias(template.templateId)));
|
|
304
|
+
}
|
|
305
|
+
function templateSummary(template) {
|
|
306
|
+
return {
|
|
307
|
+
templateId: template.templateId,
|
|
308
|
+
version: template.version,
|
|
309
|
+
module: template.module,
|
|
310
|
+
entryFunctions: template.entryFunctions,
|
|
311
|
+
riskCategory: template.riskCategory,
|
|
312
|
+
refundDisputeBehavior: template.refundDisputeBehavior,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function stripStandardsMetadata(evidence) {
|
|
316
|
+
return {
|
|
317
|
+
protocol: evidence.protocol,
|
|
318
|
+
status: evidence.status,
|
|
319
|
+
referenceId: evidence.referenceId,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function visibility(viewer) {
|
|
323
|
+
if (viewer.role === "operator")
|
|
324
|
+
return "operator";
|
|
325
|
+
if (viewer.role === "reviewer")
|
|
326
|
+
return "reviewer";
|
|
327
|
+
return "party";
|
|
328
|
+
}
|
|
329
|
+
function pickString(record, key) {
|
|
330
|
+
const value = stringValue(record[key]);
|
|
331
|
+
return value ? { [key]: value } : {};
|
|
332
|
+
}
|
|
333
|
+
function templateIdAlias(templateId) {
|
|
334
|
+
return templateId.replace(/_v(\d+)$/, ":v$1");
|
|
335
|
+
}
|
|
336
|
+
function isEscrowReceipt(receipt) {
|
|
337
|
+
return "escrow" in receipt;
|
|
338
|
+
}
|
|
339
|
+
function stringValue(value) {
|
|
340
|
+
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
341
|
+
}
|
|
342
|
+
function isString(value) {
|
|
343
|
+
return typeof value === "string";
|
|
344
|
+
}
|
|
345
|
+
function isRecord(value) {
|
|
346
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
347
|
+
}
|
|
348
|
+
function isSecretKey(key) {
|
|
349
|
+
return /^(seed|mnemonic|privateKey|private_key|rawKeypair|raw_keypair|rawTransactionBytes|raw_transaction_bytes|userSignature|user_signature|sponsorKey|sponsor_key|appApiKey|app_api_key|bearerToken|bearer_token|paymentCredential|payment_credential|signerSecret|signer_secret|signerRef|signer_ref|walletId|wallet_id|credentialRefs|credential_refs|metadata|privatePrompt|private_prompt|prompt|paymentPayload|payment_payload)$/i.test(key);
|
|
350
|
+
}
|
|
351
|
+
function redactString(value) {
|
|
352
|
+
return value
|
|
353
|
+
.replace(/Bearer\s+[A-Za-z0-9._-]+/gi, "[REDACTED]")
|
|
354
|
+
.replace(/private prompt[^,.]*/gi, "[REDACTED]")
|
|
355
|
+
.replace(/signer_ref[\w:-]*/gi, "[REDACTED]")
|
|
356
|
+
.replace(/wallet_[\w:-]*/gi, "[REDACTED]")
|
|
357
|
+
.replace(/payment-secret/gi, "[REDACTED]");
|
|
358
|
+
}
|
|
359
|
+
function responseLeaks(text) {
|
|
360
|
+
return /private prompt|Bearer abc|signer_ref|wallet_demo|payment-secret|secret provider|PRIVATE KEY|BEGIN PRIVATE/i.test(text);
|
|
361
|
+
}
|
|
362
|
+
function stableStringify(value) {
|
|
363
|
+
if (Array.isArray(value))
|
|
364
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
365
|
+
if (!isRecord(value))
|
|
366
|
+
return JSON.stringify(value);
|
|
367
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(",")}}`;
|
|
368
|
+
}
|
|
369
|
+
function sha256(value) {
|
|
370
|
+
return createHash("sha256").update(value).digest("hex");
|
|
371
|
+
}
|
|
372
|
+
function validProfile() {
|
|
373
|
+
return {
|
|
374
|
+
...validAgentProfileFixture(),
|
|
375
|
+
capabilities: [{
|
|
376
|
+
id: "research.summary",
|
|
377
|
+
contracts: ["escrow:v1"],
|
|
378
|
+
scopes: ["contract:escrow"],
|
|
379
|
+
}],
|
|
380
|
+
endpoints: [
|
|
381
|
+
{ type: "mcp", url: "https://agent.example.test/mcp" },
|
|
382
|
+
{ type: "agent_card", url: "https://agent.example.test/.well-known/agent-card.json" },
|
|
383
|
+
],
|
|
384
|
+
supportedContracts: [{ id: "escrow:v1" }],
|
|
385
|
+
};
|
|
386
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vallum/marketplace",
|
|
3
|
+
"version": "0.0.0-prerelease",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@vallum/contracts-metadata": "0.0.0-prerelease",
|
|
16
|
+
"@vallum/manifest": "0.0.0-prerelease",
|
|
17
|
+
"@vallum/policy-gateway": "0.0.0-prerelease",
|
|
18
|
+
"@vallum/receipts": "0.0.0-prerelease",
|
|
19
|
+
"@vallum/registry": "0.0.0-prerelease"
|
|
20
|
+
},
|
|
21
|
+
"description": "Read-only local marketplace evidence views for Vallum.",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/**/*.js",
|
|
24
|
+
"dist/**/*.d.ts",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p tsconfig.build.json"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public",
|
|
37
|
+
"tag": "next"
|
|
38
|
+
}
|
|
39
|
+
}
|