@probemesh/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 +22 -0
- package/README.md +160 -0
- package/dist/chunk-257Y7LN2.js +827 -0
- package/dist/chunk-257Y7LN2.js.map +1 -0
- package/dist/chunk-2ASMVLG4.js +56 -0
- package/dist/chunk-2ASMVLG4.js.map +1 -0
- package/dist/chunk-2KWGHJYP.js +285 -0
- package/dist/chunk-2KWGHJYP.js.map +1 -0
- package/dist/chunk-3H7UGVI6.js +1117 -0
- package/dist/chunk-3H7UGVI6.js.map +1 -0
- package/dist/chunk-5Q3PDYIA.js +657 -0
- package/dist/chunk-5Q3PDYIA.js.map +1 -0
- package/dist/chunk-CXZOO3U4.js +550 -0
- package/dist/chunk-CXZOO3U4.js.map +1 -0
- package/dist/chunk-FRFBK4SY.js +270 -0
- package/dist/chunk-FRFBK4SY.js.map +1 -0
- package/dist/chunk-HJK52QJF.js +994 -0
- package/dist/chunk-HJK52QJF.js.map +1 -0
- package/dist/chunk-HNBDX7IU.js +705 -0
- package/dist/chunk-HNBDX7IU.js.map +1 -0
- package/dist/chunk-NYTV263W.js +116 -0
- package/dist/chunk-NYTV263W.js.map +1 -0
- package/dist/chunk-PXG54XOG.js +595 -0
- package/dist/chunk-PXG54XOG.js.map +1 -0
- package/dist/chunk-TDOBAMYM.js +607 -0
- package/dist/chunk-TDOBAMYM.js.map +1 -0
- package/dist/chunk-TV42EZSI.js +2157 -0
- package/dist/chunk-TV42EZSI.js.map +1 -0
- package/dist/chunk-UU2ZG7P7.js +408 -0
- package/dist/chunk-UU2ZG7P7.js.map +1 -0
- package/dist/chunk-WKN7QOCA.js +977 -0
- package/dist/chunk-WKN7QOCA.js.map +1 -0
- package/dist/chunk-ZJOLPBJJ.js +1091 -0
- package/dist/chunk-ZJOLPBJJ.js.map +1 -0
- package/dist/cli/audit-trail-export.cjs +1193 -0
- package/dist/cli/audit-trail-export.cjs.map +1 -0
- package/dist/cli/audit-trail-export.d.cts +1 -0
- package/dist/cli/audit-trail-export.d.ts +1 -0
- package/dist/cli/audit-trail-export.js +24 -0
- package/dist/cli/audit-trail-export.js.map +1 -0
- package/dist/cli/catalog-check.cjs +2687 -0
- package/dist/cli/catalog-check.cjs.map +1 -0
- package/dist/cli/catalog-check.d.cts +1 -0
- package/dist/cli/catalog-check.d.ts +1 -0
- package/dist/cli/catalog-check.js +26 -0
- package/dist/cli/catalog-check.js.map +1 -0
- package/dist/cli/probemesh-init.cjs +1049 -0
- package/dist/cli/probemesh-init.cjs.map +1 -0
- package/dist/cli/probemesh-init.d.cts +1 -0
- package/dist/cli/probemesh-init.d.ts +1 -0
- package/dist/cli/probemesh-init.js +22 -0
- package/dist/cli/probemesh-init.js.map +1 -0
- package/dist/cli/provider-conformance.cjs +6180 -0
- package/dist/cli/provider-conformance.cjs.map +1 -0
- package/dist/cli/provider-conformance.d.cts +1 -0
- package/dist/cli/provider-conformance.d.ts +1 -0
- package/dist/cli/provider-conformance.js +29 -0
- package/dist/cli/provider-conformance.js.map +1 -0
- package/dist/cli/provider-dossier-check.cjs +2978 -0
- package/dist/cli/provider-dossier-check.cjs.map +1 -0
- package/dist/cli/provider-dossier-check.d.cts +1 -0
- package/dist/cli/provider-dossier-check.d.ts +1 -0
- package/dist/cli/provider-dossier-check.js +27 -0
- package/dist/cli/provider-dossier-check.js.map +1 -0
- package/dist/cli/provider-dossier.cjs +1753 -0
- package/dist/cli/provider-dossier.cjs.map +1 -0
- package/dist/cli/provider-dossier.d.cts +1 -0
- package/dist/cli/provider-dossier.d.ts +1 -0
- package/dist/cli/provider-dossier.js +26 -0
- package/dist/cli/provider-dossier.js.map +1 -0
- package/dist/cli/x402-accept.cjs +6009 -0
- package/dist/cli/x402-accept.cjs.map +1 -0
- package/dist/cli/x402-accept.d.cts +1 -0
- package/dist/cli/x402-accept.d.ts +1 -0
- package/dist/cli/x402-accept.js +28 -0
- package/dist/cli/x402-accept.js.map +1 -0
- package/dist/index.cjs +13671 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2026 -0
- package/dist/index.d.ts +2026 -0
- package/dist/index.js +2560 -0
- package/dist/index.js.map +1 -0
- package/package.json +111 -0
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateProviderConformanceArtifact
|
|
3
|
+
} from "./chunk-UU2ZG7P7.js";
|
|
4
|
+
import {
|
|
5
|
+
validateProviderCatalogArtifact
|
|
6
|
+
} from "./chunk-3H7UGVI6.js";
|
|
7
|
+
import {
|
|
8
|
+
redactX402Secrets
|
|
9
|
+
} from "./chunk-NYTV263W.js";
|
|
10
|
+
import {
|
|
11
|
+
ProbeMeshError
|
|
12
|
+
} from "./chunk-2ASMVLG4.js";
|
|
13
|
+
|
|
14
|
+
// src/providerOnboardingDossier.ts
|
|
15
|
+
import { createHash } from "crypto";
|
|
16
|
+
var PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION = "probemesh.provider-onboarding-dossier.v1";
|
|
17
|
+
function createProviderOnboardingDossier(options) {
|
|
18
|
+
assertProviderOnboardingDossierOptions(options);
|
|
19
|
+
const status = options.catalogArtifact.status === "ready" && options.conformanceArtifact.status === "verified" ? "ready" : "failed";
|
|
20
|
+
const readiness = summarizeReadiness(
|
|
21
|
+
options.catalogArtifact,
|
|
22
|
+
options.conformanceArtifact,
|
|
23
|
+
status
|
|
24
|
+
);
|
|
25
|
+
const baseContent = sanitizeDossierOutput(
|
|
26
|
+
{
|
|
27
|
+
schemaVersion: PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION,
|
|
28
|
+
dossierId: options.dossierId ?? `${options.catalogArtifact.provider.id}:${options.catalogArtifact.artifactId}:${options.conformanceArtifact.artifactId}:dossier`,
|
|
29
|
+
generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
30
|
+
status,
|
|
31
|
+
hashAlgorithm: "sha256",
|
|
32
|
+
provider: summarizeProvider(options.catalogArtifact),
|
|
33
|
+
readiness,
|
|
34
|
+
evidence: summarizeEvidence(
|
|
35
|
+
options.catalogArtifact,
|
|
36
|
+
options.conformanceArtifact
|
|
37
|
+
),
|
|
38
|
+
artifacts: {
|
|
39
|
+
catalog: cloneSerializable(options.catalogArtifact),
|
|
40
|
+
conformance: cloneSerializable(options.conformanceArtifact)
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
options.forbiddenOutputValues ?? []
|
|
44
|
+
);
|
|
45
|
+
const hashesWithoutDossier = {
|
|
46
|
+
catalogArtifact: hashStableJson(baseContent.artifacts.catalog),
|
|
47
|
+
conformanceArtifact: hashStableJson(baseContent.artifacts.conformance),
|
|
48
|
+
readiness: hashStableJson(baseContent.readiness),
|
|
49
|
+
dossier: ""
|
|
50
|
+
};
|
|
51
|
+
const dossier = {
|
|
52
|
+
...baseContent,
|
|
53
|
+
hashes: {
|
|
54
|
+
...hashesWithoutDossier,
|
|
55
|
+
dossier: hashDossierContent({
|
|
56
|
+
...baseContent,
|
|
57
|
+
hashes: hashesWithoutDossier
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
assertProviderOnboardingDossier(dossier);
|
|
62
|
+
return dossier;
|
|
63
|
+
}
|
|
64
|
+
function validateProviderOnboardingDossier(dossier) {
|
|
65
|
+
const errors = [];
|
|
66
|
+
if (!isRecord(dossier)) {
|
|
67
|
+
return {
|
|
68
|
+
valid: false,
|
|
69
|
+
errors: [
|
|
70
|
+
{
|
|
71
|
+
path: "$",
|
|
72
|
+
message: "Provider onboarding dossier must be an object."
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (dossier.schemaVersion !== PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION) {
|
|
78
|
+
errors.push({
|
|
79
|
+
path: "schemaVersion",
|
|
80
|
+
message: `schemaVersion must be "${PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION}".`
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
validateNonEmptyString(dossier.dossierId, "dossierId", errors);
|
|
84
|
+
validateIsoTimestamp(dossier.generatedAt, "generatedAt", errors);
|
|
85
|
+
if (dossier.status !== "ready" && dossier.status !== "failed") {
|
|
86
|
+
errors.push({
|
|
87
|
+
path: "status",
|
|
88
|
+
message: 'status must be "ready" or "failed".'
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (dossier.hashAlgorithm !== "sha256") {
|
|
92
|
+
errors.push({
|
|
93
|
+
path: "hashAlgorithm",
|
|
94
|
+
message: 'hashAlgorithm must be "sha256".'
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
validateProviderSummary(dossier.provider, errors);
|
|
98
|
+
validateReadiness(dossier.readiness, errors);
|
|
99
|
+
validateEvidence(dossier.evidence, errors);
|
|
100
|
+
validateNestedArtifacts(dossier.artifacts, errors);
|
|
101
|
+
validateHashes(dossier, errors);
|
|
102
|
+
return {
|
|
103
|
+
valid: errors.length === 0,
|
|
104
|
+
errors
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function assertProviderOnboardingDossier(dossier) {
|
|
108
|
+
const result = validateProviderOnboardingDossier(dossier);
|
|
109
|
+
if (result.valid) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
throw new ProbeMeshError({
|
|
113
|
+
code: "invalid_request",
|
|
114
|
+
message: `Invalid provider onboarding dossier: ${formatValidationErrors(
|
|
115
|
+
result.errors
|
|
116
|
+
)}`
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function formatProviderOnboardingDossier(dossier, options = {}) {
|
|
120
|
+
assertProviderOnboardingDossier(dossier);
|
|
121
|
+
if ((options.format ?? "json") === "markdown") {
|
|
122
|
+
return formatDossierMarkdown(dossier, options.title);
|
|
123
|
+
}
|
|
124
|
+
return JSON.stringify(dossier, null, 2);
|
|
125
|
+
}
|
|
126
|
+
function assertProviderOnboardingDossierOptions(options) {
|
|
127
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
128
|
+
throw new ProbeMeshError({
|
|
129
|
+
code: "invalid_request",
|
|
130
|
+
message: "Provider onboarding dossier options must be an object."
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
const catalogValidation = validateProviderCatalogArtifact(
|
|
134
|
+
options.catalogArtifact
|
|
135
|
+
);
|
|
136
|
+
if (!catalogValidation.valid) {
|
|
137
|
+
throw new ProbeMeshError({
|
|
138
|
+
code: "invalid_request",
|
|
139
|
+
message: `Invalid provider onboarding catalog artifact: ${formatValidationErrors(
|
|
140
|
+
catalogValidation.errors
|
|
141
|
+
)}`
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const conformanceValidation = validateProviderConformanceArtifact(
|
|
145
|
+
options.conformanceArtifact
|
|
146
|
+
);
|
|
147
|
+
if (!conformanceValidation.valid) {
|
|
148
|
+
throw new ProbeMeshError({
|
|
149
|
+
code: "invalid_request",
|
|
150
|
+
message: `Invalid provider onboarding conformance artifact: ${formatValidationErrors(
|
|
151
|
+
conformanceValidation.errors
|
|
152
|
+
)}`
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (options.catalogArtifact.provider.id !== options.conformanceArtifact.provider.id) {
|
|
156
|
+
throw new ProbeMeshError({
|
|
157
|
+
code: "invalid_request",
|
|
158
|
+
message: "Provider onboarding dossier requires catalog and conformance artifacts for the same provider id."
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (options.generatedAt !== void 0 && (typeof options.generatedAt !== "string" || Number.isNaN(Date.parse(options.generatedAt)))) {
|
|
162
|
+
throw new ProbeMeshError({
|
|
163
|
+
code: "invalid_request",
|
|
164
|
+
message: "Provider onboarding dossier generatedAt must be an ISO timestamp."
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (options.dossierId !== void 0 && (typeof options.dossierId !== "string" || options.dossierId.length === 0)) {
|
|
168
|
+
throw new ProbeMeshError({
|
|
169
|
+
code: "invalid_request",
|
|
170
|
+
message: "Provider onboarding dossier dossierId must be a non-empty string."
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (options.forbiddenOutputValues !== void 0 && (!Array.isArray(options.forbiddenOutputValues) || options.forbiddenOutputValues.some((value) => typeof value !== "string"))) {
|
|
174
|
+
throw new ProbeMeshError({
|
|
175
|
+
code: "invalid_request",
|
|
176
|
+
message: "Provider onboarding dossier forbiddenOutputValues must be an array of strings."
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function summarizeProvider(catalogArtifact) {
|
|
181
|
+
return {
|
|
182
|
+
id: catalogArtifact.provider.id,
|
|
183
|
+
displayName: catalogArtifact.provider.displayName,
|
|
184
|
+
capabilities: [...catalogArtifact.provider.capabilities],
|
|
185
|
+
protocolMode: catalogArtifact.provider.protocolMode,
|
|
186
|
+
pricing: cloneSerializable(catalogArtifact.provider.pricing),
|
|
187
|
+
paymentOptions: cloneSerializable(catalogArtifact.provider.paymentOptions)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function summarizeReadiness(catalogArtifact, conformanceArtifact, status) {
|
|
191
|
+
const reasons = [];
|
|
192
|
+
const failedChecks = [];
|
|
193
|
+
if (catalogArtifact.status === "ready") {
|
|
194
|
+
reasons.push("Catalog artifact is ready.");
|
|
195
|
+
} else {
|
|
196
|
+
reasons.push("Catalog artifact is rejected.");
|
|
197
|
+
failedChecks.push("catalog_not_ready");
|
|
198
|
+
}
|
|
199
|
+
if (conformanceArtifact.status === "verified") {
|
|
200
|
+
reasons.push("Conformance artifact is verified.");
|
|
201
|
+
} else {
|
|
202
|
+
reasons.push("Conformance artifact failed.");
|
|
203
|
+
failedChecks.push("conformance_not_verified");
|
|
204
|
+
}
|
|
205
|
+
for (const check of catalogArtifact.acceptance.failedChecks) {
|
|
206
|
+
failedChecks.push(`catalog:${check}`);
|
|
207
|
+
}
|
|
208
|
+
for (const check of conformanceArtifact.conformance.failedChecks) {
|
|
209
|
+
failedChecks.push(`conformance:${check}`);
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
ready: status === "ready",
|
|
213
|
+
status,
|
|
214
|
+
reasons,
|
|
215
|
+
failedChecks: uniqueStrings(failedChecks)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function summarizeEvidence(catalogArtifact, conformanceArtifact) {
|
|
219
|
+
return {
|
|
220
|
+
catalog: {
|
|
221
|
+
artifactId: catalogArtifact.artifactId,
|
|
222
|
+
status: catalogArtifact.status,
|
|
223
|
+
acceptanceStatus: catalogArtifact.acceptance.status,
|
|
224
|
+
gateStatus: catalogArtifact.acceptance.gate.status,
|
|
225
|
+
accepted: catalogArtifact.acceptance.gate.accepted,
|
|
226
|
+
failedChecks: [...catalogArtifact.acceptance.failedChecks]
|
|
227
|
+
},
|
|
228
|
+
conformance: {
|
|
229
|
+
artifactId: conformanceArtifact.artifactId,
|
|
230
|
+
status: conformanceArtifact.status,
|
|
231
|
+
conformanceStatus: conformanceArtifact.conformance.status,
|
|
232
|
+
failedChecks: [...conformanceArtifact.conformance.failedChecks]
|
|
233
|
+
},
|
|
234
|
+
receipts: combineReceiptSummaries(
|
|
235
|
+
catalogArtifact.acceptance.receipts,
|
|
236
|
+
conformanceArtifact.conformance.receipts
|
|
237
|
+
),
|
|
238
|
+
safety: {
|
|
239
|
+
acceptance: cloneSerializable(catalogArtifact.acceptance.safety),
|
|
240
|
+
conformance: cloneSerializable(conformanceArtifact.conformance.safety)
|
|
241
|
+
},
|
|
242
|
+
retrySafety: {
|
|
243
|
+
acceptance: cloneSerializable(catalogArtifact.acceptance.retrySafety),
|
|
244
|
+
conformance: cloneSerializable(conformanceArtifact.conformance.retrySafety)
|
|
245
|
+
},
|
|
246
|
+
route: {
|
|
247
|
+
acceptance: cloneSerializable(catalogArtifact.acceptance.route),
|
|
248
|
+
conformance: cloneSerializable(conformanceArtifact.conformance.route)
|
|
249
|
+
},
|
|
250
|
+
timelineEventTypes: uniqueStrings([
|
|
251
|
+
...catalogArtifact.acceptance.timelineEventTypes,
|
|
252
|
+
...conformanceArtifact.conformance.timelineEventTypes
|
|
253
|
+
]),
|
|
254
|
+
telemetryEventTypes: uniqueStrings([
|
|
255
|
+
...catalogArtifact.acceptance.telemetryEventTypes,
|
|
256
|
+
...conformanceArtifact.conformance.telemetryEventTypes
|
|
257
|
+
])
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function combineReceiptSummaries(left, right) {
|
|
261
|
+
const byType = {};
|
|
262
|
+
for (const [type, count] of Object.entries(left.byType)) {
|
|
263
|
+
byType[type] = (byType[type] ?? 0) + Number(count);
|
|
264
|
+
}
|
|
265
|
+
for (const [type, count] of Object.entries(right.byType)) {
|
|
266
|
+
byType[type] = (byType[type] ?? 0) + Number(count);
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
total: left.total + right.total,
|
|
270
|
+
types: uniqueStrings([...left.types, ...right.types]),
|
|
271
|
+
providers: uniqueStrings([...left.providers, ...right.providers]),
|
|
272
|
+
byType,
|
|
273
|
+
hasPaymentProof: left.hasPaymentProof || right.hasPaymentProof,
|
|
274
|
+
hasSettlementConfirmation: left.hasSettlementConfirmation || right.hasSettlementConfirmation,
|
|
275
|
+
hasProviderDelivery: left.hasProviderDelivery || right.hasProviderDelivery
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function formatDossierMarkdown(dossier, title) {
|
|
279
|
+
const lines = [
|
|
280
|
+
`# ${title ?? `${dossier.provider.displayName} Onboarding Dossier`}`,
|
|
281
|
+
"",
|
|
282
|
+
`Status: ${dossier.status}`,
|
|
283
|
+
`Schema: ${dossier.schemaVersion}`,
|
|
284
|
+
`Dossier ID: ${dossier.dossierId}`,
|
|
285
|
+
`Generated: ${dossier.generatedAt}`,
|
|
286
|
+
`Provider: ${dossier.provider.id}`,
|
|
287
|
+
`Capabilities: ${formatInlineList(dossier.provider.capabilities)}`,
|
|
288
|
+
"",
|
|
289
|
+
"## Readiness",
|
|
290
|
+
`- Ready: ${String(dossier.readiness.ready)}`,
|
|
291
|
+
`- Reasons: ${formatInlineList(dossier.readiness.reasons)}`,
|
|
292
|
+
`- Failed checks: ${formatInlineList(dossier.readiness.failedChecks)}`,
|
|
293
|
+
"",
|
|
294
|
+
"## Evidence",
|
|
295
|
+
`- Catalog artifact: ${dossier.evidence.catalog.artifactId} (${dossier.evidence.catalog.status})`,
|
|
296
|
+
`- Conformance artifact: ${dossier.evidence.conformance.artifactId} (${dossier.evidence.conformance.status})`,
|
|
297
|
+
`- Receipts: ${formatInlineList(dossier.evidence.receipts.types)}`,
|
|
298
|
+
`- Timeline: ${formatInlineList(dossier.evidence.timelineEventTypes)}`,
|
|
299
|
+
"",
|
|
300
|
+
"## Safety",
|
|
301
|
+
`- Acceptance payment: ${dossier.evidence.safety.acceptance?.paymentStatus ?? "unknown"}`,
|
|
302
|
+
`- Conformance payment: ${dossier.evidence.safety.conformance?.paymentStatus ?? "unknown"}`,
|
|
303
|
+
`- Acceptance delivery: ${dossier.evidence.safety.acceptance?.deliveryStatus ?? "unknown"}`,
|
|
304
|
+
`- Conformance delivery: ${dossier.evidence.safety.conformance?.deliveryStatus ?? "unknown"}`,
|
|
305
|
+
"",
|
|
306
|
+
"## Hashes",
|
|
307
|
+
`- Catalog artifact: ${dossier.hashes.catalogArtifact}`,
|
|
308
|
+
`- Conformance artifact: ${dossier.hashes.conformanceArtifact}`,
|
|
309
|
+
`- Readiness: ${dossier.hashes.readiness}`,
|
|
310
|
+
`- Dossier: ${dossier.hashes.dossier}`
|
|
311
|
+
];
|
|
312
|
+
return `${lines.join("\n")}
|
|
313
|
+
`;
|
|
314
|
+
}
|
|
315
|
+
function validateProviderSummary(provider, errors) {
|
|
316
|
+
if (!isRecord(provider)) {
|
|
317
|
+
errors.push({
|
|
318
|
+
path: "provider",
|
|
319
|
+
message: "provider must be an object."
|
|
320
|
+
});
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
validateNonEmptyString(provider.id, "provider.id", errors);
|
|
324
|
+
validateNonEmptyString(provider.displayName, "provider.displayName", errors);
|
|
325
|
+
validateNonEmptyString(provider.protocolMode, "provider.protocolMode", errors);
|
|
326
|
+
if (!Array.isArray(provider.capabilities) || provider.capabilities.some((capability) => typeof capability !== "string")) {
|
|
327
|
+
errors.push({
|
|
328
|
+
path: "provider.capabilities",
|
|
329
|
+
message: "provider.capabilities must be an array of strings."
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function validateReadiness(readiness, errors) {
|
|
334
|
+
if (!isRecord(readiness)) {
|
|
335
|
+
errors.push({
|
|
336
|
+
path: "readiness",
|
|
337
|
+
message: "readiness must be an object."
|
|
338
|
+
});
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (typeof readiness.ready !== "boolean") {
|
|
342
|
+
errors.push({
|
|
343
|
+
path: "readiness.ready",
|
|
344
|
+
message: "readiness.ready must be a boolean."
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
if (readiness.status !== "ready" && readiness.status !== "failed") {
|
|
348
|
+
errors.push({
|
|
349
|
+
path: "readiness.status",
|
|
350
|
+
message: 'readiness.status must be "ready" or "failed".'
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
if (!Array.isArray(readiness.reasons) || readiness.reasons.some((reason) => typeof reason !== "string")) {
|
|
354
|
+
errors.push({
|
|
355
|
+
path: "readiness.reasons",
|
|
356
|
+
message: "readiness.reasons must be an array of strings."
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
if (!Array.isArray(readiness.failedChecks) || readiness.failedChecks.some((check) => typeof check !== "string")) {
|
|
360
|
+
errors.push({
|
|
361
|
+
path: "readiness.failedChecks",
|
|
362
|
+
message: "readiness.failedChecks must be an array of strings."
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function validateEvidence(evidence, errors) {
|
|
367
|
+
if (!isRecord(evidence)) {
|
|
368
|
+
errors.push({
|
|
369
|
+
path: "evidence",
|
|
370
|
+
message: "evidence must be an object."
|
|
371
|
+
});
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (!isRecord(evidence.catalog)) {
|
|
375
|
+
errors.push({
|
|
376
|
+
path: "evidence.catalog",
|
|
377
|
+
message: "evidence.catalog must be an object."
|
|
378
|
+
});
|
|
379
|
+
} else {
|
|
380
|
+
validateNonEmptyString(
|
|
381
|
+
evidence.catalog.artifactId,
|
|
382
|
+
"evidence.catalog.artifactId",
|
|
383
|
+
errors
|
|
384
|
+
);
|
|
385
|
+
if (evidence.catalog.status !== "ready" && evidence.catalog.status !== "rejected") {
|
|
386
|
+
errors.push({
|
|
387
|
+
path: "evidence.catalog.status",
|
|
388
|
+
message: 'evidence.catalog.status must be "ready" or "rejected".'
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
if (typeof evidence.catalog.accepted !== "boolean") {
|
|
392
|
+
errors.push({
|
|
393
|
+
path: "evidence.catalog.accepted",
|
|
394
|
+
message: "evidence.catalog.accepted must be a boolean."
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (!isRecord(evidence.conformance)) {
|
|
399
|
+
errors.push({
|
|
400
|
+
path: "evidence.conformance",
|
|
401
|
+
message: "evidence.conformance must be an object."
|
|
402
|
+
});
|
|
403
|
+
} else {
|
|
404
|
+
validateNonEmptyString(
|
|
405
|
+
evidence.conformance.artifactId,
|
|
406
|
+
"evidence.conformance.artifactId",
|
|
407
|
+
errors
|
|
408
|
+
);
|
|
409
|
+
if (evidence.conformance.status !== "verified" && evidence.conformance.status !== "failed") {
|
|
410
|
+
errors.push({
|
|
411
|
+
path: "evidence.conformance.status",
|
|
412
|
+
message: 'evidence.conformance.status must be "verified" or "failed".'
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (!isRecord(evidence.receipts)) {
|
|
417
|
+
errors.push({
|
|
418
|
+
path: "evidence.receipts",
|
|
419
|
+
message: "evidence.receipts must be an object."
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
if (!Array.isArray(evidence.timelineEventTypes) || evidence.timelineEventTypes.some((type) => typeof type !== "string")) {
|
|
423
|
+
errors.push({
|
|
424
|
+
path: "evidence.timelineEventTypes",
|
|
425
|
+
message: "evidence.timelineEventTypes must be an array of strings."
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
if (!Array.isArray(evidence.telemetryEventTypes) || evidence.telemetryEventTypes.some((type) => typeof type !== "string")) {
|
|
429
|
+
errors.push({
|
|
430
|
+
path: "evidence.telemetryEventTypes",
|
|
431
|
+
message: "evidence.telemetryEventTypes must be an array of strings."
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function validateNestedArtifacts(artifacts, errors) {
|
|
436
|
+
if (!isRecord(artifacts)) {
|
|
437
|
+
errors.push({
|
|
438
|
+
path: "artifacts",
|
|
439
|
+
message: "artifacts must be an object."
|
|
440
|
+
});
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
const catalogValidation = validateProviderCatalogArtifact(artifacts.catalog);
|
|
444
|
+
for (const error of catalogValidation.errors) {
|
|
445
|
+
errors.push({
|
|
446
|
+
path: `artifacts.catalog.${error.path}`,
|
|
447
|
+
message: error.message
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
const conformanceValidation = validateProviderConformanceArtifact(
|
|
451
|
+
artifacts.conformance
|
|
452
|
+
);
|
|
453
|
+
for (const error of conformanceValidation.errors) {
|
|
454
|
+
errors.push({
|
|
455
|
+
path: `artifacts.conformance.${error.path}`,
|
|
456
|
+
message: error.message
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
if (isRecord(artifacts.catalog) && isRecord(artifacts.conformance) && isRecord(artifacts.catalog.provider) && isRecord(artifacts.conformance.provider) && artifacts.catalog.provider.id !== artifacts.conformance.provider.id) {
|
|
460
|
+
errors.push({
|
|
461
|
+
path: "artifacts",
|
|
462
|
+
message: "catalog and conformance artifacts must reference the same provider id."
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
function validateHashes(dossier, errors) {
|
|
467
|
+
if (!isRecord(dossier.hashes)) {
|
|
468
|
+
errors.push({
|
|
469
|
+
path: "hashes",
|
|
470
|
+
message: "hashes must be an object."
|
|
471
|
+
});
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
for (const field of [
|
|
475
|
+
"catalogArtifact",
|
|
476
|
+
"conformanceArtifact",
|
|
477
|
+
"readiness",
|
|
478
|
+
"dossier"
|
|
479
|
+
]) {
|
|
480
|
+
const value = dossier.hashes[field];
|
|
481
|
+
if (typeof value !== "string" || !/^[a-f0-9]{64}$/.test(value)) {
|
|
482
|
+
errors.push({
|
|
483
|
+
path: `hashes.${field}`,
|
|
484
|
+
message: `${field} hash must be a sha256 hex string.`
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (!isRecord(dossier.artifacts) || !isRecord(dossier.readiness) || errors.some((error) => error.path.startsWith("hashes."))) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const expectedHashes = {
|
|
492
|
+
catalogArtifact: hashStableJson(dossier.artifacts.catalog),
|
|
493
|
+
conformanceArtifact: hashStableJson(dossier.artifacts.conformance),
|
|
494
|
+
readiness: hashStableJson(dossier.readiness),
|
|
495
|
+
dossier: ""
|
|
496
|
+
};
|
|
497
|
+
const expectedDossierHash = hashDossierContent({
|
|
498
|
+
...dossier,
|
|
499
|
+
hashes: expectedHashes
|
|
500
|
+
});
|
|
501
|
+
for (const [field, expected] of Object.entries({
|
|
502
|
+
...expectedHashes,
|
|
503
|
+
dossier: expectedDossierHash
|
|
504
|
+
})) {
|
|
505
|
+
if (dossier.hashes[field] !== expected) {
|
|
506
|
+
errors.push({
|
|
507
|
+
path: `hashes.${field}`,
|
|
508
|
+
message: `${field} hash does not match dossier content.`
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function sanitizeDossierOutput(value, forbiddenOutputValues) {
|
|
514
|
+
const forbiddenValues = forbiddenOutputValues.filter((entry) => entry.length > 0);
|
|
515
|
+
return redactX402Secrets(
|
|
516
|
+
replaceForbiddenValues(value, forbiddenValues, /* @__PURE__ */ new WeakSet())
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
function replaceForbiddenValues(value, forbiddenValues, seen) {
|
|
520
|
+
if (typeof value === "string") {
|
|
521
|
+
return forbiddenValues.reduce(
|
|
522
|
+
(current, forbidden) => current.split(forbidden).join("[REDACTED]"),
|
|
523
|
+
value
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
if (value === null || typeof value !== "object" || value instanceof Date) {
|
|
527
|
+
return value;
|
|
528
|
+
}
|
|
529
|
+
if (seen.has(value)) {
|
|
530
|
+
return "[Circular]";
|
|
531
|
+
}
|
|
532
|
+
seen.add(value);
|
|
533
|
+
if (Array.isArray(value)) {
|
|
534
|
+
const entries2 = value.map(
|
|
535
|
+
(entry) => replaceForbiddenValues(entry, forbiddenValues, seen)
|
|
536
|
+
);
|
|
537
|
+
seen.delete(value);
|
|
538
|
+
return entries2;
|
|
539
|
+
}
|
|
540
|
+
const entries = Object.fromEntries(
|
|
541
|
+
Object.entries(value).map(([key, entry]) => [
|
|
542
|
+
key,
|
|
543
|
+
replaceForbiddenValues(entry, forbiddenValues, seen)
|
|
544
|
+
])
|
|
545
|
+
);
|
|
546
|
+
seen.delete(value);
|
|
547
|
+
return entries;
|
|
548
|
+
}
|
|
549
|
+
function cloneSerializable(value) {
|
|
550
|
+
if (value === void 0) {
|
|
551
|
+
return value;
|
|
552
|
+
}
|
|
553
|
+
return JSON.parse(JSON.stringify(value));
|
|
554
|
+
}
|
|
555
|
+
function hashStableJson(value) {
|
|
556
|
+
return createHash("sha256").update(stableStringify(value)).digest("hex");
|
|
557
|
+
}
|
|
558
|
+
function hashDossierContent(dossier) {
|
|
559
|
+
return hashStableJson(dossier);
|
|
560
|
+
}
|
|
561
|
+
function stableStringify(value) {
|
|
562
|
+
if (value === null || typeof value !== "object") {
|
|
563
|
+
return JSON.stringify(value);
|
|
564
|
+
}
|
|
565
|
+
if (Array.isArray(value)) {
|
|
566
|
+
return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
567
|
+
}
|
|
568
|
+
const entries = Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([left], [right]) => left.localeCompare(right));
|
|
569
|
+
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(",")}}`;
|
|
570
|
+
}
|
|
571
|
+
function uniqueStrings(values) {
|
|
572
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
573
|
+
}
|
|
574
|
+
function formatInlineList(values) {
|
|
575
|
+
return values.length > 0 ? values.join(", ") : "none";
|
|
576
|
+
}
|
|
577
|
+
function isRecord(value) {
|
|
578
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
579
|
+
}
|
|
580
|
+
function validateNonEmptyString(value, path, errors) {
|
|
581
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
582
|
+
errors.push({
|
|
583
|
+
path,
|
|
584
|
+
message: `${path} must be a non-empty string.`
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function validateIsoTimestamp(value, path, errors) {
|
|
589
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {
|
|
590
|
+
errors.push({
|
|
591
|
+
path,
|
|
592
|
+
message: `${path} must be an ISO timestamp.`
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
function formatValidationErrors(errors) {
|
|
597
|
+
return errors.map((error) => `${error.path}: ${error.message}`).join("; ");
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export {
|
|
601
|
+
PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION,
|
|
602
|
+
createProviderOnboardingDossier,
|
|
603
|
+
validateProviderOnboardingDossier,
|
|
604
|
+
assertProviderOnboardingDossier,
|
|
605
|
+
formatProviderOnboardingDossier
|
|
606
|
+
};
|
|
607
|
+
//# sourceMappingURL=chunk-TDOBAMYM.js.map
|