@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,1753 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/cli/providerOnboardingDossierCli.ts
|
|
5
|
+
var import_promises2 = require("fs/promises");
|
|
6
|
+
var import_node_path2 = require("path");
|
|
7
|
+
|
|
8
|
+
// src/cli/configLoader.ts
|
|
9
|
+
var import_promises = require("fs/promises");
|
|
10
|
+
var import_node_path = require("path");
|
|
11
|
+
var import_node_url = require("url");
|
|
12
|
+
async function loadCliConfigDefault(configPath, cwd) {
|
|
13
|
+
const resolvedPath = (0, import_node_path.resolve)(cwd, configPath);
|
|
14
|
+
const moduleUrl = (0, import_node_url.pathToFileURL)(resolvedPath);
|
|
15
|
+
try {
|
|
16
|
+
const loadedModule = await import(
|
|
17
|
+
/* @vite-ignore */
|
|
18
|
+
moduleUrl.href
|
|
19
|
+
);
|
|
20
|
+
return loadedModule.default;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return loadSelfContainedConfigFallback(resolvedPath, error);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function loadSelfContainedConfigFallback(resolvedPath, importError) {
|
|
26
|
+
const source = await (0, import_promises.readFile)(resolvedPath, "utf8");
|
|
27
|
+
if (/\bimport\s/.test(source) || !/\bexport\s+default\b/.test(source)) {
|
|
28
|
+
throw importError;
|
|
29
|
+
}
|
|
30
|
+
const transformedSource = source.replace(
|
|
31
|
+
/\bexport\s+default\b/,
|
|
32
|
+
"const __probemeshDefault ="
|
|
33
|
+
);
|
|
34
|
+
try {
|
|
35
|
+
const factory = new Function(
|
|
36
|
+
`${transformedSource}
|
|
37
|
+
return __probemeshDefault;`
|
|
38
|
+
);
|
|
39
|
+
return factory();
|
|
40
|
+
} catch {
|
|
41
|
+
throw importError;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/errors.ts
|
|
46
|
+
var ProbeMeshError = class extends Error {
|
|
47
|
+
code;
|
|
48
|
+
status = "failed";
|
|
49
|
+
capability;
|
|
50
|
+
provider;
|
|
51
|
+
callId;
|
|
52
|
+
receiptRefs;
|
|
53
|
+
safety;
|
|
54
|
+
timeline;
|
|
55
|
+
retrySafety;
|
|
56
|
+
attempt;
|
|
57
|
+
route;
|
|
58
|
+
cause;
|
|
59
|
+
constructor(options) {
|
|
60
|
+
super(options.message);
|
|
61
|
+
this.name = "ProbeMeshError";
|
|
62
|
+
this.code = options.code;
|
|
63
|
+
this.capability = options.capability;
|
|
64
|
+
this.provider = options.provider;
|
|
65
|
+
this.callId = options.callId;
|
|
66
|
+
this.receiptRefs = options.receiptRefs;
|
|
67
|
+
this.safety = options.safety;
|
|
68
|
+
this.timeline = options.timeline;
|
|
69
|
+
this.retrySafety = options.retrySafety;
|
|
70
|
+
this.attempt = options.attempt;
|
|
71
|
+
this.route = options.route;
|
|
72
|
+
this.cause = options.cause;
|
|
73
|
+
}
|
|
74
|
+
toJSON() {
|
|
75
|
+
return {
|
|
76
|
+
name: this.name,
|
|
77
|
+
code: this.code,
|
|
78
|
+
message: this.message,
|
|
79
|
+
status: this.status,
|
|
80
|
+
capability: this.capability,
|
|
81
|
+
provider: this.provider,
|
|
82
|
+
callId: this.callId,
|
|
83
|
+
receiptRefs: this.receiptRefs,
|
|
84
|
+
safety: this.safety,
|
|
85
|
+
timeline: this.timeline,
|
|
86
|
+
retrySafety: this.retrySafety,
|
|
87
|
+
attempt: this.attempt,
|
|
88
|
+
route: this.route
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/paymentOptions.ts
|
|
94
|
+
function validateProviderPaymentOptions(paymentOptions, path, capabilities, errors) {
|
|
95
|
+
if (paymentOptions === void 0) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!Array.isArray(paymentOptions) || paymentOptions.length === 0) {
|
|
99
|
+
errors.push({
|
|
100
|
+
path,
|
|
101
|
+
message: "paymentOptions must be a non-empty array when provided."
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const seen = /* @__PURE__ */ new Set();
|
|
106
|
+
paymentOptions.forEach((option, index) => {
|
|
107
|
+
const optionPath = `${path}.${index}`;
|
|
108
|
+
if (!isRecord(option)) {
|
|
109
|
+
errors.push({
|
|
110
|
+
path: optionPath,
|
|
111
|
+
message: "payment option must be an object."
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
validateNonEmptyString(option.id, `${optionPath}.id`, errors);
|
|
116
|
+
validateNonEmptyString(option.protocolMode, `${optionPath}.protocolMode`, errors);
|
|
117
|
+
if (typeof option.id === "string") {
|
|
118
|
+
if (seen.has(option.id)) {
|
|
119
|
+
errors.push({
|
|
120
|
+
path: `${optionPath}.id`,
|
|
121
|
+
message: `duplicate payment option "${option.id}".`
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
seen.add(option.id);
|
|
125
|
+
}
|
|
126
|
+
if (option.capabilities !== void 0) {
|
|
127
|
+
validateStringArray(option.capabilities, `${optionPath}.capabilities`, errors);
|
|
128
|
+
if (Array.isArray(option.capabilities)) {
|
|
129
|
+
for (const capability of option.capabilities) {
|
|
130
|
+
if (typeof capability === "string" && capability.length > 0 && !capabilities.includes(capability)) {
|
|
131
|
+
errors.push({
|
|
132
|
+
path: `${optionPath}.capabilities`,
|
|
133
|
+
message: `payment option capability "${capability}" is not declared by the provider.`
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (option.pricing !== void 0) {
|
|
140
|
+
validatePricingDeclaration(option.pricing, `${optionPath}.pricing`, errors);
|
|
141
|
+
}
|
|
142
|
+
if (option.receiptTypes !== void 0) {
|
|
143
|
+
if (!Array.isArray(option.receiptTypes) || option.receiptTypes.some((receiptType) => !isReceiptType(receiptType))) {
|
|
144
|
+
errors.push({
|
|
145
|
+
path: `${optionPath}.receiptTypes`,
|
|
146
|
+
message: "payment option receiptTypes must contain known receipt types."
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (option.metadata !== void 0 && !isRecord(option.metadata)) {
|
|
151
|
+
errors.push({
|
|
152
|
+
path: `${optionPath}.metadata`,
|
|
153
|
+
message: "payment option metadata must be an object when provided."
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function validatePricingDeclaration(pricing, path, errors) {
|
|
159
|
+
if (!isRecord(pricing)) {
|
|
160
|
+
errors.push({
|
|
161
|
+
path,
|
|
162
|
+
message: "payment option pricing must be an object."
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (isPricing(pricing)) {
|
|
167
|
+
validatePricing(pricing, path, errors);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
for (const [capability, capabilityPricing] of Object.entries(pricing)) {
|
|
171
|
+
validatePricing(capabilityPricing, `${path}.${capability}`, errors);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function validatePricing(pricing, path, errors) {
|
|
175
|
+
if (!isRecord(pricing)) {
|
|
176
|
+
errors.push({
|
|
177
|
+
path,
|
|
178
|
+
message: "payment option pricing entry must be an object."
|
|
179
|
+
});
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
validateNonEmptyString(pricing.unit, `${path}.unit`, errors);
|
|
183
|
+
if (typeof pricing.amountUsd !== "number" || !Number.isFinite(pricing.amountUsd) || pricing.amountUsd < 0) {
|
|
184
|
+
errors.push({
|
|
185
|
+
path: `${path}.amountUsd`,
|
|
186
|
+
message: "amountUsd must be a non-negative number."
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (pricing.currency !== void 0 && typeof pricing.currency !== "string") {
|
|
190
|
+
errors.push({
|
|
191
|
+
path: `${path}.currency`,
|
|
192
|
+
message: "currency must be a string when provided."
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function validateStringArray(value, path, errors) {
|
|
197
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string" || entry.length === 0)) {
|
|
198
|
+
errors.push({
|
|
199
|
+
path,
|
|
200
|
+
message: `${path} must be an array of non-empty strings.`
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function validateNonEmptyString(value, path, errors) {
|
|
205
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
206
|
+
errors.push({
|
|
207
|
+
path,
|
|
208
|
+
message: `${path} must be a non-empty string.`
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function isPricing(value) {
|
|
213
|
+
return isRecord(value) && typeof value.unit === "string" && value.unit.length > 0 && typeof value.amountUsd === "number" && Number.isFinite(value.amountUsd) && value.amountUsd >= 0 && (value.currency === void 0 || typeof value.currency === "string");
|
|
214
|
+
}
|
|
215
|
+
function isReceiptType(value) {
|
|
216
|
+
return value === "payment_proof" || value === "settlement_confirmation" || value === "provider_delivery" || value === "provider_response_evidence" || value === "authorization_decision";
|
|
217
|
+
}
|
|
218
|
+
function isRecord(value) {
|
|
219
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/providerKit/manifest.ts
|
|
223
|
+
var JSON_SCHEMA_HINT_KEYS = /* @__PURE__ */ new Set([
|
|
224
|
+
"$schema",
|
|
225
|
+
"$id",
|
|
226
|
+
"type",
|
|
227
|
+
"properties",
|
|
228
|
+
"required",
|
|
229
|
+
"items",
|
|
230
|
+
"enum",
|
|
231
|
+
"description",
|
|
232
|
+
"additionalProperties",
|
|
233
|
+
"oneOf",
|
|
234
|
+
"anyOf",
|
|
235
|
+
"allOf"
|
|
236
|
+
]);
|
|
237
|
+
function validateProviderManifest(manifest) {
|
|
238
|
+
const errors = [];
|
|
239
|
+
if (!isRecord2(manifest)) {
|
|
240
|
+
return {
|
|
241
|
+
valid: false,
|
|
242
|
+
errors: [
|
|
243
|
+
{
|
|
244
|
+
path: "$",
|
|
245
|
+
message: "Provider manifest must be an object."
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
validateNonEmptyString2(manifest.id, "id", errors);
|
|
251
|
+
validateNonEmptyString2(manifest.displayName, "displayName", errors);
|
|
252
|
+
validateCapabilityList(manifest.capabilities, errors);
|
|
253
|
+
validateNonEmptyString2(manifest.protocolMode, "protocolMode", errors);
|
|
254
|
+
validateProviderPaymentOptions(
|
|
255
|
+
manifest.paymentOptions,
|
|
256
|
+
"paymentOptions",
|
|
257
|
+
Array.isArray(manifest.capabilities) ? manifest.capabilities : [],
|
|
258
|
+
errors
|
|
259
|
+
);
|
|
260
|
+
validatePricingDeclaration2(
|
|
261
|
+
manifest.pricing,
|
|
262
|
+
"pricing",
|
|
263
|
+
manifest.capabilities,
|
|
264
|
+
errors
|
|
265
|
+
);
|
|
266
|
+
validateSchemaDeclaration(
|
|
267
|
+
manifest.inputSchema,
|
|
268
|
+
"inputSchema",
|
|
269
|
+
manifest.capabilities,
|
|
270
|
+
errors
|
|
271
|
+
);
|
|
272
|
+
validateSchemaDeclaration(
|
|
273
|
+
manifest.outputSchema,
|
|
274
|
+
"outputSchema",
|
|
275
|
+
manifest.capabilities,
|
|
276
|
+
errors
|
|
277
|
+
);
|
|
278
|
+
validateReceipts(manifest.receipts, errors);
|
|
279
|
+
if (manifest.limits !== void 0) {
|
|
280
|
+
validateLimits(manifest.limits, errors);
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
valid: errors.length === 0,
|
|
284
|
+
errors
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function isSharedJsonSchemaLike(value) {
|
|
288
|
+
if (!isRecord2(value)) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
return Object.keys(value).some((key) => JSON_SCHEMA_HINT_KEYS.has(key));
|
|
292
|
+
}
|
|
293
|
+
function isSharedPricing(value) {
|
|
294
|
+
return isRecord2(value) && typeof value.unit === "string" && value.unit.length > 0 && typeof value.amountUsd === "number";
|
|
295
|
+
}
|
|
296
|
+
function validateCapabilityList(capabilities, errors) {
|
|
297
|
+
if (!Array.isArray(capabilities) || capabilities.length === 0) {
|
|
298
|
+
errors.push({
|
|
299
|
+
path: "capabilities",
|
|
300
|
+
message: "capabilities must be a non-empty array."
|
|
301
|
+
});
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const seen = /* @__PURE__ */ new Set();
|
|
305
|
+
capabilities.forEach((capability, index) => {
|
|
306
|
+
if (typeof capability !== "string" || capability.length === 0) {
|
|
307
|
+
errors.push({
|
|
308
|
+
path: `capabilities.${index}`,
|
|
309
|
+
message: "capability ids must be non-empty strings."
|
|
310
|
+
});
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (seen.has(capability)) {
|
|
314
|
+
errors.push({
|
|
315
|
+
path: `capabilities.${index}`,
|
|
316
|
+
message: `duplicate capability "${capability}".`
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
seen.add(capability);
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
function validatePricingDeclaration2(pricing, path, capabilities, errors) {
|
|
323
|
+
if (!isRecord2(pricing)) {
|
|
324
|
+
errors.push({
|
|
325
|
+
path,
|
|
326
|
+
message: "pricing must be an object."
|
|
327
|
+
});
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (isSharedPricing(pricing)) {
|
|
331
|
+
validatePricing2(pricing, path, errors);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (!Array.isArray(capabilities)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
for (const capability of capabilities) {
|
|
338
|
+
if (typeof capability !== "string" || capability.length === 0) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
validatePricing2(pricing[capability], `${path}.${capability}`, errors);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function validatePricing2(pricing, path, errors) {
|
|
345
|
+
if (!isRecord2(pricing)) {
|
|
346
|
+
errors.push({
|
|
347
|
+
path,
|
|
348
|
+
message: "pricing entry must be an object."
|
|
349
|
+
});
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
validateNonEmptyString2(pricing.unit, `${path}.unit`, errors);
|
|
353
|
+
if (typeof pricing.amountUsd !== "number" || !Number.isFinite(pricing.amountUsd) || pricing.amountUsd < 0) {
|
|
354
|
+
errors.push({
|
|
355
|
+
path: `${path}.amountUsd`,
|
|
356
|
+
message: "amountUsd must be a non-negative number."
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
if (pricing.currency !== void 0 && typeof pricing.currency !== "string") {
|
|
360
|
+
errors.push({
|
|
361
|
+
path: `${path}.currency`,
|
|
362
|
+
message: "currency must be a string when provided."
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function validateSchemaDeclaration(schema, path, capabilities, errors) {
|
|
367
|
+
if (!isRecord2(schema)) {
|
|
368
|
+
errors.push({
|
|
369
|
+
path,
|
|
370
|
+
message: `${path} must be an object.`
|
|
371
|
+
});
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (isSharedJsonSchemaLike(schema)) {
|
|
375
|
+
validateSchemaLike(schema, path, errors);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (!Array.isArray(capabilities)) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
for (const capability of capabilities) {
|
|
382
|
+
if (typeof capability !== "string" || capability.length === 0) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
validateSchemaLike(schema[capability], `${path}.${capability}`, errors);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function validateSchemaLike(schema, path, errors) {
|
|
389
|
+
if (!isRecord2(schema)) {
|
|
390
|
+
errors.push({
|
|
391
|
+
path,
|
|
392
|
+
message: "schema entry must be an object."
|
|
393
|
+
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (schema.type !== void 0 && typeof schema.type !== "string") {
|
|
397
|
+
errors.push({
|
|
398
|
+
path: `${path}.type`,
|
|
399
|
+
message: "schema type must be a string when provided."
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
if (schema.properties !== void 0 && !isRecord2(schema.properties)) {
|
|
403
|
+
errors.push({
|
|
404
|
+
path: `${path}.properties`,
|
|
405
|
+
message: "schema properties must be an object when provided."
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
if (schema.required !== void 0 && (!Array.isArray(schema.required) || schema.required.some((field) => typeof field !== "string"))) {
|
|
409
|
+
errors.push({
|
|
410
|
+
path: `${path}.required`,
|
|
411
|
+
message: "schema required must be an array of strings when provided."
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function validateReceipts(receipts, errors) {
|
|
416
|
+
if (!isRecord2(receipts)) {
|
|
417
|
+
errors.push({
|
|
418
|
+
path: "receipts",
|
|
419
|
+
message: "receipts must be an object."
|
|
420
|
+
});
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
validateBoolean(receipts.payment, "receipts.payment", errors);
|
|
424
|
+
validateBoolean(receipts.delivery, "receipts.delivery", errors);
|
|
425
|
+
validateBoolean(
|
|
426
|
+
receipts.responseEvidence,
|
|
427
|
+
"receipts.responseEvidence",
|
|
428
|
+
errors
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
function validateLimits(limits, errors) {
|
|
432
|
+
if (!isRecord2(limits)) {
|
|
433
|
+
errors.push({
|
|
434
|
+
path: "limits",
|
|
435
|
+
message: "limits must be an object when provided."
|
|
436
|
+
});
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const typedLimits = limits;
|
|
440
|
+
if (typedLimits.maxRequestsPerMinute !== void 0 && (!Number.isFinite(typedLimits.maxRequestsPerMinute) || typedLimits.maxRequestsPerMinute <= 0)) {
|
|
441
|
+
errors.push({
|
|
442
|
+
path: "limits.maxRequestsPerMinute",
|
|
443
|
+
message: "maxRequestsPerMinute must be a positive number when provided."
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function validateNonEmptyString2(value, path, errors) {
|
|
448
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
449
|
+
errors.push({
|
|
450
|
+
path,
|
|
451
|
+
message: `${path} must be a non-empty string.`
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function validateBoolean(value, path, errors) {
|
|
456
|
+
if (typeof value !== "boolean") {
|
|
457
|
+
errors.push({
|
|
458
|
+
path,
|
|
459
|
+
message: `${path} must be a boolean.`
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function isRecord2(value) {
|
|
464
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// src/protocols/x402Redaction.ts
|
|
468
|
+
var DEFAULT_REPLACEMENT = "[REDACTED]";
|
|
469
|
+
var DEFAULT_MAX_DEPTH = 12;
|
|
470
|
+
var PRIVATE_KEY_PATTERN = /\b0x[a-fA-F0-9]{64}\b/g;
|
|
471
|
+
var HEX_SIGNATURE_PATTERN = /\b0x[a-fA-F0-9]{130}\b/g;
|
|
472
|
+
var SECRET_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
473
|
+
"api-key",
|
|
474
|
+
"apikey",
|
|
475
|
+
"authorization",
|
|
476
|
+
"bearer",
|
|
477
|
+
"payment-required",
|
|
478
|
+
"payment-response",
|
|
479
|
+
"payment-signature",
|
|
480
|
+
"privatekey",
|
|
481
|
+
"signature",
|
|
482
|
+
"x-api-key"
|
|
483
|
+
]);
|
|
484
|
+
function redactX402Secrets(value, options = {}) {
|
|
485
|
+
const replacement = options.replacement ?? DEFAULT_REPLACEMENT;
|
|
486
|
+
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
487
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
488
|
+
return redactValue(value, {
|
|
489
|
+
replacement,
|
|
490
|
+
maxDepth,
|
|
491
|
+
depth: 0,
|
|
492
|
+
seen,
|
|
493
|
+
key: void 0
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
function redactValue(value, context) {
|
|
497
|
+
if (context.key && shouldRedactKey(context.key)) {
|
|
498
|
+
return context.replacement;
|
|
499
|
+
}
|
|
500
|
+
if (typeof value === "string") {
|
|
501
|
+
return redactString(value, context.replacement);
|
|
502
|
+
}
|
|
503
|
+
if (value === null || typeof value !== "object" || value instanceof Date) {
|
|
504
|
+
return value;
|
|
505
|
+
}
|
|
506
|
+
if (context.depth >= context.maxDepth) {
|
|
507
|
+
return "[MaxDepth]";
|
|
508
|
+
}
|
|
509
|
+
if (context.seen.has(value)) {
|
|
510
|
+
return "[Circular]";
|
|
511
|
+
}
|
|
512
|
+
context.seen.add(value);
|
|
513
|
+
if (Array.isArray(value)) {
|
|
514
|
+
return value.map(
|
|
515
|
+
(entry) => redactValue(entry, {
|
|
516
|
+
...context,
|
|
517
|
+
depth: context.depth + 1,
|
|
518
|
+
key: void 0
|
|
519
|
+
})
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
return Object.fromEntries(
|
|
523
|
+
Object.entries(value).map(([key, entry]) => [
|
|
524
|
+
key,
|
|
525
|
+
redactValue(entry, {
|
|
526
|
+
...context,
|
|
527
|
+
depth: context.depth + 1,
|
|
528
|
+
key
|
|
529
|
+
})
|
|
530
|
+
])
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
function shouldRedactKey(key) {
|
|
534
|
+
const normalized = key.toLowerCase().replace(/_/g, "-");
|
|
535
|
+
return SECRET_FIELD_NAMES.has(normalized) || normalized.includes("private-key") || normalized.includes("privatekey") || normalized.includes("payment-signature") || normalized.includes("payment-response") || normalized.includes("payment-required") || normalized.includes("api-key");
|
|
536
|
+
}
|
|
537
|
+
function redactString(value, replacement) {
|
|
538
|
+
return value.replace(PRIVATE_KEY_PATTERN, replacement).replace(HEX_SIGNATURE_PATTERN, replacement);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/providerCatalogArtifact.ts
|
|
542
|
+
var PROVIDER_CATALOG_ARTIFACT_SCHEMA_VERSION = "probemesh.provider-catalog.v1";
|
|
543
|
+
function validateProviderCatalogArtifact(artifact) {
|
|
544
|
+
const errors = [];
|
|
545
|
+
if (!isRecord3(artifact)) {
|
|
546
|
+
return {
|
|
547
|
+
valid: false,
|
|
548
|
+
errors: [
|
|
549
|
+
{
|
|
550
|
+
path: "$",
|
|
551
|
+
message: "Provider catalog artifact must be an object."
|
|
552
|
+
}
|
|
553
|
+
]
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (artifact.schemaVersion !== PROVIDER_CATALOG_ARTIFACT_SCHEMA_VERSION) {
|
|
557
|
+
errors.push({
|
|
558
|
+
path: "schemaVersion",
|
|
559
|
+
message: `schemaVersion must be "${PROVIDER_CATALOG_ARTIFACT_SCHEMA_VERSION}".`
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
validateNonEmptyString3(artifact.artifactId, "artifactId", errors);
|
|
563
|
+
validateIsoTimestamp(artifact.generatedAt, "generatedAt", errors);
|
|
564
|
+
if (artifact.status !== "ready" && artifact.status !== "rejected") {
|
|
565
|
+
errors.push({
|
|
566
|
+
path: "status",
|
|
567
|
+
message: 'status must be "ready" or "rejected".'
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
const manifestValidation = validateProviderManifest(artifact.provider);
|
|
571
|
+
for (const manifestError of manifestValidation.errors) {
|
|
572
|
+
errors.push({
|
|
573
|
+
path: `provider.${manifestError.path}`,
|
|
574
|
+
message: manifestError.message
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
validateAcceptanceArtifact(artifact.acceptance, errors);
|
|
578
|
+
return {
|
|
579
|
+
valid: errors.length === 0,
|
|
580
|
+
errors
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
function assertProviderCatalogArtifact(artifact) {
|
|
584
|
+
const result = validateProviderCatalogArtifact(artifact);
|
|
585
|
+
if (result.valid) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
throw new ProbeMeshError({
|
|
589
|
+
code: "invalid_request",
|
|
590
|
+
message: `Invalid provider catalog artifact: ${formatValidationErrors(result.errors)}`
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
function validateAcceptanceArtifact(acceptance, errors) {
|
|
594
|
+
if (!isRecord3(acceptance)) {
|
|
595
|
+
errors.push({
|
|
596
|
+
path: "acceptance",
|
|
597
|
+
message: "acceptance must be an object."
|
|
598
|
+
});
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
validateNonEmptyString3(acceptance.title, "acceptance.title", errors);
|
|
602
|
+
if (acceptance.status !== "passed" && acceptance.status !== "failed") {
|
|
603
|
+
errors.push({
|
|
604
|
+
path: "acceptance.status",
|
|
605
|
+
message: 'acceptance.status must be "passed" or "failed".'
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (!isRecord3(acceptance.gate)) {
|
|
609
|
+
errors.push({
|
|
610
|
+
path: "acceptance.gate",
|
|
611
|
+
message: "acceptance.gate must be an object."
|
|
612
|
+
});
|
|
613
|
+
} else {
|
|
614
|
+
if (typeof acceptance.gate.accepted !== "boolean") {
|
|
615
|
+
errors.push({
|
|
616
|
+
path: "acceptance.gate.accepted",
|
|
617
|
+
message: "acceptance.gate.accepted must be a boolean."
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
if (acceptance.gate.status !== "accepted" && acceptance.gate.status !== "rejected") {
|
|
621
|
+
errors.push({
|
|
622
|
+
path: "acceptance.gate.status",
|
|
623
|
+
message: 'acceptance.gate.status must be "accepted" or "rejected".'
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
validateStringArray2(
|
|
628
|
+
acceptance.failedChecks,
|
|
629
|
+
"acceptance.failedChecks",
|
|
630
|
+
errors
|
|
631
|
+
);
|
|
632
|
+
validateReceiptSummary(acceptance.receipts, errors);
|
|
633
|
+
validateStringArray2(
|
|
634
|
+
acceptance.timelineEventTypes,
|
|
635
|
+
"acceptance.timelineEventTypes",
|
|
636
|
+
errors
|
|
637
|
+
);
|
|
638
|
+
validateStringArray2(
|
|
639
|
+
acceptance.telemetryEventTypes,
|
|
640
|
+
"acceptance.telemetryEventTypes",
|
|
641
|
+
errors
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
function validateReceiptSummary(receipts, errors) {
|
|
645
|
+
if (!isRecord3(receipts)) {
|
|
646
|
+
errors.push({
|
|
647
|
+
path: "acceptance.receipts",
|
|
648
|
+
message: "acceptance.receipts must be an object."
|
|
649
|
+
});
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
if (typeof receipts.total !== "number" || !Number.isFinite(receipts.total)) {
|
|
653
|
+
errors.push({
|
|
654
|
+
path: "acceptance.receipts.total",
|
|
655
|
+
message: "acceptance.receipts.total must be a number."
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
validateStringArray2(receipts.types, "acceptance.receipts.types", errors);
|
|
659
|
+
validateStringArray2(
|
|
660
|
+
receipts.providers,
|
|
661
|
+
"acceptance.receipts.providers",
|
|
662
|
+
errors
|
|
663
|
+
);
|
|
664
|
+
for (const key of [
|
|
665
|
+
"hasPaymentProof",
|
|
666
|
+
"hasSettlementConfirmation",
|
|
667
|
+
"hasProviderDelivery"
|
|
668
|
+
]) {
|
|
669
|
+
if (typeof receipts[key] !== "boolean") {
|
|
670
|
+
errors.push({
|
|
671
|
+
path: `acceptance.receipts.${key}`,
|
|
672
|
+
message: `acceptance.receipts.${key} must be a boolean.`
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function validateStringArray2(value, path, errors) {
|
|
678
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
679
|
+
errors.push({
|
|
680
|
+
path,
|
|
681
|
+
message: `${path} must be an array of strings.`
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
function validateNonEmptyString3(value, path, errors) {
|
|
686
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
687
|
+
errors.push({
|
|
688
|
+
path,
|
|
689
|
+
message: `${path} must be a non-empty string.`
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function validateIsoTimestamp(value, path, errors) {
|
|
694
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {
|
|
695
|
+
errors.push({
|
|
696
|
+
path,
|
|
697
|
+
message: `${path} must be an ISO timestamp string.`
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
function formatValidationErrors(errors) {
|
|
702
|
+
return errors.map((error) => `${error.path}: ${error.message}`).join("; ");
|
|
703
|
+
}
|
|
704
|
+
function isRecord3(value) {
|
|
705
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// src/providerConformanceArtifact.ts
|
|
709
|
+
var import_node_crypto = require("crypto");
|
|
710
|
+
var PROVIDER_CONFORMANCE_ARTIFACT_SCHEMA_VERSION = "probemesh.provider-conformance.v1";
|
|
711
|
+
function validateProviderConformanceArtifact(artifact) {
|
|
712
|
+
const errors = [];
|
|
713
|
+
if (!isRecord4(artifact)) {
|
|
714
|
+
return {
|
|
715
|
+
valid: false,
|
|
716
|
+
errors: [
|
|
717
|
+
{
|
|
718
|
+
path: "$",
|
|
719
|
+
message: "Provider conformance artifact must be an object."
|
|
720
|
+
}
|
|
721
|
+
]
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
if (artifact.schemaVersion !== PROVIDER_CONFORMANCE_ARTIFACT_SCHEMA_VERSION) {
|
|
725
|
+
errors.push({
|
|
726
|
+
path: "schemaVersion",
|
|
727
|
+
message: `schemaVersion must be "${PROVIDER_CONFORMANCE_ARTIFACT_SCHEMA_VERSION}".`
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
validateNonEmptyString4(artifact.artifactId, "artifactId", errors);
|
|
731
|
+
validateIsoTimestamp2(artifact.generatedAt, "generatedAt", errors);
|
|
732
|
+
if (artifact.status !== "verified" && artifact.status !== "failed") {
|
|
733
|
+
errors.push({
|
|
734
|
+
path: "status",
|
|
735
|
+
message: 'status must be "verified" or "failed".'
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
if (artifact.hashAlgorithm !== "sha256") {
|
|
739
|
+
errors.push({
|
|
740
|
+
path: "hashAlgorithm",
|
|
741
|
+
message: 'hashAlgorithm must be "sha256".'
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
validateHashes(artifact.hashes, errors);
|
|
745
|
+
validateManifestSummary(artifact.provider, errors);
|
|
746
|
+
validateConformanceSummary(artifact.conformance, errors);
|
|
747
|
+
return {
|
|
748
|
+
valid: errors.length === 0,
|
|
749
|
+
errors
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function assertProviderConformanceArtifact(artifact) {
|
|
753
|
+
const result = validateProviderConformanceArtifact(artifact);
|
|
754
|
+
if (result.valid) {
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
throw new ProbeMeshError({
|
|
758
|
+
code: "invalid_request",
|
|
759
|
+
message: `Invalid provider conformance artifact: ${formatValidationErrors2(
|
|
760
|
+
result.errors
|
|
761
|
+
)}`
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
function validateManifestSummary(provider, errors) {
|
|
765
|
+
if (!isRecord4(provider)) {
|
|
766
|
+
errors.push({
|
|
767
|
+
path: "provider",
|
|
768
|
+
message: "provider must be an object."
|
|
769
|
+
});
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
validateNonEmptyString4(provider.id, "provider.id", errors);
|
|
773
|
+
validateNonEmptyString4(provider.displayName, "provider.displayName", errors);
|
|
774
|
+
if (!Array.isArray(provider.capabilities) || provider.capabilities.some((capability) => typeof capability !== "string")) {
|
|
775
|
+
errors.push({
|
|
776
|
+
path: "provider.capabilities",
|
|
777
|
+
message: "provider.capabilities must be an array of strings."
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
validateNonEmptyString4(provider.protocolMode, "provider.protocolMode", errors);
|
|
781
|
+
if (!isRecord4(provider.receipts)) {
|
|
782
|
+
errors.push({
|
|
783
|
+
path: "provider.receipts",
|
|
784
|
+
message: "provider.receipts must be an object."
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
if (!isRecord4(provider.schemas) || typeof provider.schemas.inputDeclared !== "boolean" || typeof provider.schemas.outputDeclared !== "boolean") {
|
|
788
|
+
errors.push({
|
|
789
|
+
path: "provider.schemas",
|
|
790
|
+
message: "provider.schemas must include inputDeclared and outputDeclared booleans."
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function validateConformanceSummary(conformance, errors) {
|
|
795
|
+
if (!isRecord4(conformance)) {
|
|
796
|
+
errors.push({
|
|
797
|
+
path: "conformance",
|
|
798
|
+
message: "conformance must be an object."
|
|
799
|
+
});
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
validateNonEmptyString4(conformance.title, "conformance.title", errors);
|
|
803
|
+
if (conformance.status !== "passed" && conformance.status !== "failed") {
|
|
804
|
+
errors.push({
|
|
805
|
+
path: "conformance.status",
|
|
806
|
+
message: 'conformance.status must be "passed" or "failed".'
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
if (!isRecord4(conformance.summary)) {
|
|
810
|
+
errors.push({
|
|
811
|
+
path: "conformance.summary",
|
|
812
|
+
message: "conformance.summary must be an object."
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
if (!Array.isArray(conformance.checks) || conformance.checks.some((check) => !isRecord4(check))) {
|
|
816
|
+
errors.push({
|
|
817
|
+
path: "conformance.checks",
|
|
818
|
+
message: "conformance.checks must be an array of check objects."
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
if (!Array.isArray(conformance.failedChecks) || conformance.failedChecks.some((checkName) => typeof checkName !== "string")) {
|
|
822
|
+
errors.push({
|
|
823
|
+
path: "conformance.failedChecks",
|
|
824
|
+
message: "conformance.failedChecks must be an array of strings."
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
if (!isRecord4(conformance.receipts)) {
|
|
828
|
+
errors.push({
|
|
829
|
+
path: "conformance.receipts",
|
|
830
|
+
message: "conformance.receipts must be an object."
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
if (!Array.isArray(conformance.timelineEventTypes) || conformance.timelineEventTypes.some((eventType) => typeof eventType !== "string")) {
|
|
834
|
+
errors.push({
|
|
835
|
+
path: "conformance.timelineEventTypes",
|
|
836
|
+
message: "conformance.timelineEventTypes must be an array of strings."
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
if (!Array.isArray(conformance.telemetryEventTypes) || conformance.telemetryEventTypes.some((eventType) => typeof eventType !== "string")) {
|
|
840
|
+
errors.push({
|
|
841
|
+
path: "conformance.telemetryEventTypes",
|
|
842
|
+
message: "conformance.telemetryEventTypes must be an array of strings."
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
function validateHashes(hashes, errors) {
|
|
847
|
+
if (!isRecord4(hashes)) {
|
|
848
|
+
errors.push({
|
|
849
|
+
path: "hashes",
|
|
850
|
+
message: "hashes must be an object."
|
|
851
|
+
});
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
for (const field of ["manifest", "report", "checks", "artifact"]) {
|
|
855
|
+
const value = hashes[field];
|
|
856
|
+
if (typeof value !== "string" || !/^[a-f0-9]{64}$/.test(value)) {
|
|
857
|
+
errors.push({
|
|
858
|
+
path: `hashes.${field}`,
|
|
859
|
+
message: `${field} hash must be a sha256 hex string.`
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
function validateNonEmptyString4(value, path, errors) {
|
|
865
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
866
|
+
errors.push({
|
|
867
|
+
path,
|
|
868
|
+
message: `${path} must be a non-empty string.`
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
function validateIsoTimestamp2(value, path, errors) {
|
|
873
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {
|
|
874
|
+
errors.push({
|
|
875
|
+
path,
|
|
876
|
+
message: `${path} must be an ISO timestamp.`
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
function formatValidationErrors2(errors) {
|
|
881
|
+
return errors.map((error) => `${error.path}: ${error.message}`).join("; ");
|
|
882
|
+
}
|
|
883
|
+
function isRecord4(value) {
|
|
884
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// src/providerOnboardingDossier.ts
|
|
888
|
+
var import_node_crypto2 = require("crypto");
|
|
889
|
+
var PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION = "probemesh.provider-onboarding-dossier.v1";
|
|
890
|
+
function createProviderOnboardingDossier(options) {
|
|
891
|
+
assertProviderOnboardingDossierOptions(options);
|
|
892
|
+
const status = options.catalogArtifact.status === "ready" && options.conformanceArtifact.status === "verified" ? "ready" : "failed";
|
|
893
|
+
const readiness = summarizeReadiness(
|
|
894
|
+
options.catalogArtifact,
|
|
895
|
+
options.conformanceArtifact,
|
|
896
|
+
status
|
|
897
|
+
);
|
|
898
|
+
const baseContent = sanitizeDossierOutput(
|
|
899
|
+
{
|
|
900
|
+
schemaVersion: PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION,
|
|
901
|
+
dossierId: options.dossierId ?? `${options.catalogArtifact.provider.id}:${options.catalogArtifact.artifactId}:${options.conformanceArtifact.artifactId}:dossier`,
|
|
902
|
+
generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
903
|
+
status,
|
|
904
|
+
hashAlgorithm: "sha256",
|
|
905
|
+
provider: summarizeProvider(options.catalogArtifact),
|
|
906
|
+
readiness,
|
|
907
|
+
evidence: summarizeEvidence(
|
|
908
|
+
options.catalogArtifact,
|
|
909
|
+
options.conformanceArtifact
|
|
910
|
+
),
|
|
911
|
+
artifacts: {
|
|
912
|
+
catalog: cloneSerializable(options.catalogArtifact),
|
|
913
|
+
conformance: cloneSerializable(options.conformanceArtifact)
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
options.forbiddenOutputValues ?? []
|
|
917
|
+
);
|
|
918
|
+
const hashesWithoutDossier = {
|
|
919
|
+
catalogArtifact: hashStableJson(baseContent.artifacts.catalog),
|
|
920
|
+
conformanceArtifact: hashStableJson(baseContent.artifacts.conformance),
|
|
921
|
+
readiness: hashStableJson(baseContent.readiness),
|
|
922
|
+
dossier: ""
|
|
923
|
+
};
|
|
924
|
+
const dossier = {
|
|
925
|
+
...baseContent,
|
|
926
|
+
hashes: {
|
|
927
|
+
...hashesWithoutDossier,
|
|
928
|
+
dossier: hashDossierContent({
|
|
929
|
+
...baseContent,
|
|
930
|
+
hashes: hashesWithoutDossier
|
|
931
|
+
})
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
assertProviderOnboardingDossier(dossier);
|
|
935
|
+
return dossier;
|
|
936
|
+
}
|
|
937
|
+
function validateProviderOnboardingDossier(dossier) {
|
|
938
|
+
const errors = [];
|
|
939
|
+
if (!isRecord5(dossier)) {
|
|
940
|
+
return {
|
|
941
|
+
valid: false,
|
|
942
|
+
errors: [
|
|
943
|
+
{
|
|
944
|
+
path: "$",
|
|
945
|
+
message: "Provider onboarding dossier must be an object."
|
|
946
|
+
}
|
|
947
|
+
]
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
if (dossier.schemaVersion !== PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION) {
|
|
951
|
+
errors.push({
|
|
952
|
+
path: "schemaVersion",
|
|
953
|
+
message: `schemaVersion must be "${PROVIDER_ONBOARDING_DOSSIER_SCHEMA_VERSION}".`
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
validateNonEmptyString5(dossier.dossierId, "dossierId", errors);
|
|
957
|
+
validateIsoTimestamp3(dossier.generatedAt, "generatedAt", errors);
|
|
958
|
+
if (dossier.status !== "ready" && dossier.status !== "failed") {
|
|
959
|
+
errors.push({
|
|
960
|
+
path: "status",
|
|
961
|
+
message: 'status must be "ready" or "failed".'
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
if (dossier.hashAlgorithm !== "sha256") {
|
|
965
|
+
errors.push({
|
|
966
|
+
path: "hashAlgorithm",
|
|
967
|
+
message: 'hashAlgorithm must be "sha256".'
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
validateProviderSummary(dossier.provider, errors);
|
|
971
|
+
validateReadiness(dossier.readiness, errors);
|
|
972
|
+
validateEvidence(dossier.evidence, errors);
|
|
973
|
+
validateNestedArtifacts(dossier.artifacts, errors);
|
|
974
|
+
validateHashes2(dossier, errors);
|
|
975
|
+
return {
|
|
976
|
+
valid: errors.length === 0,
|
|
977
|
+
errors
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
function assertProviderOnboardingDossier(dossier) {
|
|
981
|
+
const result = validateProviderOnboardingDossier(dossier);
|
|
982
|
+
if (result.valid) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
throw new ProbeMeshError({
|
|
986
|
+
code: "invalid_request",
|
|
987
|
+
message: `Invalid provider onboarding dossier: ${formatValidationErrors3(
|
|
988
|
+
result.errors
|
|
989
|
+
)}`
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
function formatProviderOnboardingDossier(dossier, options = {}) {
|
|
993
|
+
assertProviderOnboardingDossier(dossier);
|
|
994
|
+
if ((options.format ?? "json") === "markdown") {
|
|
995
|
+
return formatDossierMarkdown(dossier, options.title);
|
|
996
|
+
}
|
|
997
|
+
return JSON.stringify(dossier, null, 2);
|
|
998
|
+
}
|
|
999
|
+
function assertProviderOnboardingDossierOptions(options) {
|
|
1000
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1001
|
+
throw new ProbeMeshError({
|
|
1002
|
+
code: "invalid_request",
|
|
1003
|
+
message: "Provider onboarding dossier options must be an object."
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
const catalogValidation = validateProviderCatalogArtifact(
|
|
1007
|
+
options.catalogArtifact
|
|
1008
|
+
);
|
|
1009
|
+
if (!catalogValidation.valid) {
|
|
1010
|
+
throw new ProbeMeshError({
|
|
1011
|
+
code: "invalid_request",
|
|
1012
|
+
message: `Invalid provider onboarding catalog artifact: ${formatValidationErrors3(
|
|
1013
|
+
catalogValidation.errors
|
|
1014
|
+
)}`
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
const conformanceValidation = validateProviderConformanceArtifact(
|
|
1018
|
+
options.conformanceArtifact
|
|
1019
|
+
);
|
|
1020
|
+
if (!conformanceValidation.valid) {
|
|
1021
|
+
throw new ProbeMeshError({
|
|
1022
|
+
code: "invalid_request",
|
|
1023
|
+
message: `Invalid provider onboarding conformance artifact: ${formatValidationErrors3(
|
|
1024
|
+
conformanceValidation.errors
|
|
1025
|
+
)}`
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
if (options.catalogArtifact.provider.id !== options.conformanceArtifact.provider.id) {
|
|
1029
|
+
throw new ProbeMeshError({
|
|
1030
|
+
code: "invalid_request",
|
|
1031
|
+
message: "Provider onboarding dossier requires catalog and conformance artifacts for the same provider id."
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
if (options.generatedAt !== void 0 && (typeof options.generatedAt !== "string" || Number.isNaN(Date.parse(options.generatedAt)))) {
|
|
1035
|
+
throw new ProbeMeshError({
|
|
1036
|
+
code: "invalid_request",
|
|
1037
|
+
message: "Provider onboarding dossier generatedAt must be an ISO timestamp."
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
if (options.dossierId !== void 0 && (typeof options.dossierId !== "string" || options.dossierId.length === 0)) {
|
|
1041
|
+
throw new ProbeMeshError({
|
|
1042
|
+
code: "invalid_request",
|
|
1043
|
+
message: "Provider onboarding dossier dossierId must be a non-empty string."
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
if (options.forbiddenOutputValues !== void 0 && (!Array.isArray(options.forbiddenOutputValues) || options.forbiddenOutputValues.some((value) => typeof value !== "string"))) {
|
|
1047
|
+
throw new ProbeMeshError({
|
|
1048
|
+
code: "invalid_request",
|
|
1049
|
+
message: "Provider onboarding dossier forbiddenOutputValues must be an array of strings."
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
function summarizeProvider(catalogArtifact) {
|
|
1054
|
+
return {
|
|
1055
|
+
id: catalogArtifact.provider.id,
|
|
1056
|
+
displayName: catalogArtifact.provider.displayName,
|
|
1057
|
+
capabilities: [...catalogArtifact.provider.capabilities],
|
|
1058
|
+
protocolMode: catalogArtifact.provider.protocolMode,
|
|
1059
|
+
pricing: cloneSerializable(catalogArtifact.provider.pricing),
|
|
1060
|
+
paymentOptions: cloneSerializable(catalogArtifact.provider.paymentOptions)
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
function summarizeReadiness(catalogArtifact, conformanceArtifact, status) {
|
|
1064
|
+
const reasons = [];
|
|
1065
|
+
const failedChecks = [];
|
|
1066
|
+
if (catalogArtifact.status === "ready") {
|
|
1067
|
+
reasons.push("Catalog artifact is ready.");
|
|
1068
|
+
} else {
|
|
1069
|
+
reasons.push("Catalog artifact is rejected.");
|
|
1070
|
+
failedChecks.push("catalog_not_ready");
|
|
1071
|
+
}
|
|
1072
|
+
if (conformanceArtifact.status === "verified") {
|
|
1073
|
+
reasons.push("Conformance artifact is verified.");
|
|
1074
|
+
} else {
|
|
1075
|
+
reasons.push("Conformance artifact failed.");
|
|
1076
|
+
failedChecks.push("conformance_not_verified");
|
|
1077
|
+
}
|
|
1078
|
+
for (const check of catalogArtifact.acceptance.failedChecks) {
|
|
1079
|
+
failedChecks.push(`catalog:${check}`);
|
|
1080
|
+
}
|
|
1081
|
+
for (const check of conformanceArtifact.conformance.failedChecks) {
|
|
1082
|
+
failedChecks.push(`conformance:${check}`);
|
|
1083
|
+
}
|
|
1084
|
+
return {
|
|
1085
|
+
ready: status === "ready",
|
|
1086
|
+
status,
|
|
1087
|
+
reasons,
|
|
1088
|
+
failedChecks: uniqueStrings(failedChecks)
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
function summarizeEvidence(catalogArtifact, conformanceArtifact) {
|
|
1092
|
+
return {
|
|
1093
|
+
catalog: {
|
|
1094
|
+
artifactId: catalogArtifact.artifactId,
|
|
1095
|
+
status: catalogArtifact.status,
|
|
1096
|
+
acceptanceStatus: catalogArtifact.acceptance.status,
|
|
1097
|
+
gateStatus: catalogArtifact.acceptance.gate.status,
|
|
1098
|
+
accepted: catalogArtifact.acceptance.gate.accepted,
|
|
1099
|
+
failedChecks: [...catalogArtifact.acceptance.failedChecks]
|
|
1100
|
+
},
|
|
1101
|
+
conformance: {
|
|
1102
|
+
artifactId: conformanceArtifact.artifactId,
|
|
1103
|
+
status: conformanceArtifact.status,
|
|
1104
|
+
conformanceStatus: conformanceArtifact.conformance.status,
|
|
1105
|
+
failedChecks: [...conformanceArtifact.conformance.failedChecks]
|
|
1106
|
+
},
|
|
1107
|
+
receipts: combineReceiptSummaries(
|
|
1108
|
+
catalogArtifact.acceptance.receipts,
|
|
1109
|
+
conformanceArtifact.conformance.receipts
|
|
1110
|
+
),
|
|
1111
|
+
safety: {
|
|
1112
|
+
acceptance: cloneSerializable(catalogArtifact.acceptance.safety),
|
|
1113
|
+
conformance: cloneSerializable(conformanceArtifact.conformance.safety)
|
|
1114
|
+
},
|
|
1115
|
+
retrySafety: {
|
|
1116
|
+
acceptance: cloneSerializable(catalogArtifact.acceptance.retrySafety),
|
|
1117
|
+
conformance: cloneSerializable(conformanceArtifact.conformance.retrySafety)
|
|
1118
|
+
},
|
|
1119
|
+
route: {
|
|
1120
|
+
acceptance: cloneSerializable(catalogArtifact.acceptance.route),
|
|
1121
|
+
conformance: cloneSerializable(conformanceArtifact.conformance.route)
|
|
1122
|
+
},
|
|
1123
|
+
timelineEventTypes: uniqueStrings([
|
|
1124
|
+
...catalogArtifact.acceptance.timelineEventTypes,
|
|
1125
|
+
...conformanceArtifact.conformance.timelineEventTypes
|
|
1126
|
+
]),
|
|
1127
|
+
telemetryEventTypes: uniqueStrings([
|
|
1128
|
+
...catalogArtifact.acceptance.telemetryEventTypes,
|
|
1129
|
+
...conformanceArtifact.conformance.telemetryEventTypes
|
|
1130
|
+
])
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
function combineReceiptSummaries(left, right) {
|
|
1134
|
+
const byType = {};
|
|
1135
|
+
for (const [type, count] of Object.entries(left.byType)) {
|
|
1136
|
+
byType[type] = (byType[type] ?? 0) + Number(count);
|
|
1137
|
+
}
|
|
1138
|
+
for (const [type, count] of Object.entries(right.byType)) {
|
|
1139
|
+
byType[type] = (byType[type] ?? 0) + Number(count);
|
|
1140
|
+
}
|
|
1141
|
+
return {
|
|
1142
|
+
total: left.total + right.total,
|
|
1143
|
+
types: uniqueStrings([...left.types, ...right.types]),
|
|
1144
|
+
providers: uniqueStrings([...left.providers, ...right.providers]),
|
|
1145
|
+
byType,
|
|
1146
|
+
hasPaymentProof: left.hasPaymentProof || right.hasPaymentProof,
|
|
1147
|
+
hasSettlementConfirmation: left.hasSettlementConfirmation || right.hasSettlementConfirmation,
|
|
1148
|
+
hasProviderDelivery: left.hasProviderDelivery || right.hasProviderDelivery
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
function formatDossierMarkdown(dossier, title) {
|
|
1152
|
+
const lines = [
|
|
1153
|
+
`# ${title ?? `${dossier.provider.displayName} Onboarding Dossier`}`,
|
|
1154
|
+
"",
|
|
1155
|
+
`Status: ${dossier.status}`,
|
|
1156
|
+
`Schema: ${dossier.schemaVersion}`,
|
|
1157
|
+
`Dossier ID: ${dossier.dossierId}`,
|
|
1158
|
+
`Generated: ${dossier.generatedAt}`,
|
|
1159
|
+
`Provider: ${dossier.provider.id}`,
|
|
1160
|
+
`Capabilities: ${formatInlineList(dossier.provider.capabilities)}`,
|
|
1161
|
+
"",
|
|
1162
|
+
"## Readiness",
|
|
1163
|
+
`- Ready: ${String(dossier.readiness.ready)}`,
|
|
1164
|
+
`- Reasons: ${formatInlineList(dossier.readiness.reasons)}`,
|
|
1165
|
+
`- Failed checks: ${formatInlineList(dossier.readiness.failedChecks)}`,
|
|
1166
|
+
"",
|
|
1167
|
+
"## Evidence",
|
|
1168
|
+
`- Catalog artifact: ${dossier.evidence.catalog.artifactId} (${dossier.evidence.catalog.status})`,
|
|
1169
|
+
`- Conformance artifact: ${dossier.evidence.conformance.artifactId} (${dossier.evidence.conformance.status})`,
|
|
1170
|
+
`- Receipts: ${formatInlineList(dossier.evidence.receipts.types)}`,
|
|
1171
|
+
`- Timeline: ${formatInlineList(dossier.evidence.timelineEventTypes)}`,
|
|
1172
|
+
"",
|
|
1173
|
+
"## Safety",
|
|
1174
|
+
`- Acceptance payment: ${dossier.evidence.safety.acceptance?.paymentStatus ?? "unknown"}`,
|
|
1175
|
+
`- Conformance payment: ${dossier.evidence.safety.conformance?.paymentStatus ?? "unknown"}`,
|
|
1176
|
+
`- Acceptance delivery: ${dossier.evidence.safety.acceptance?.deliveryStatus ?? "unknown"}`,
|
|
1177
|
+
`- Conformance delivery: ${dossier.evidence.safety.conformance?.deliveryStatus ?? "unknown"}`,
|
|
1178
|
+
"",
|
|
1179
|
+
"## Hashes",
|
|
1180
|
+
`- Catalog artifact: ${dossier.hashes.catalogArtifact}`,
|
|
1181
|
+
`- Conformance artifact: ${dossier.hashes.conformanceArtifact}`,
|
|
1182
|
+
`- Readiness: ${dossier.hashes.readiness}`,
|
|
1183
|
+
`- Dossier: ${dossier.hashes.dossier}`
|
|
1184
|
+
];
|
|
1185
|
+
return `${lines.join("\n")}
|
|
1186
|
+
`;
|
|
1187
|
+
}
|
|
1188
|
+
function validateProviderSummary(provider, errors) {
|
|
1189
|
+
if (!isRecord5(provider)) {
|
|
1190
|
+
errors.push({
|
|
1191
|
+
path: "provider",
|
|
1192
|
+
message: "provider must be an object."
|
|
1193
|
+
});
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
validateNonEmptyString5(provider.id, "provider.id", errors);
|
|
1197
|
+
validateNonEmptyString5(provider.displayName, "provider.displayName", errors);
|
|
1198
|
+
validateNonEmptyString5(provider.protocolMode, "provider.protocolMode", errors);
|
|
1199
|
+
if (!Array.isArray(provider.capabilities) || provider.capabilities.some((capability) => typeof capability !== "string")) {
|
|
1200
|
+
errors.push({
|
|
1201
|
+
path: "provider.capabilities",
|
|
1202
|
+
message: "provider.capabilities must be an array of strings."
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
function validateReadiness(readiness, errors) {
|
|
1207
|
+
if (!isRecord5(readiness)) {
|
|
1208
|
+
errors.push({
|
|
1209
|
+
path: "readiness",
|
|
1210
|
+
message: "readiness must be an object."
|
|
1211
|
+
});
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
if (typeof readiness.ready !== "boolean") {
|
|
1215
|
+
errors.push({
|
|
1216
|
+
path: "readiness.ready",
|
|
1217
|
+
message: "readiness.ready must be a boolean."
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
if (readiness.status !== "ready" && readiness.status !== "failed") {
|
|
1221
|
+
errors.push({
|
|
1222
|
+
path: "readiness.status",
|
|
1223
|
+
message: 'readiness.status must be "ready" or "failed".'
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
if (!Array.isArray(readiness.reasons) || readiness.reasons.some((reason) => typeof reason !== "string")) {
|
|
1227
|
+
errors.push({
|
|
1228
|
+
path: "readiness.reasons",
|
|
1229
|
+
message: "readiness.reasons must be an array of strings."
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
if (!Array.isArray(readiness.failedChecks) || readiness.failedChecks.some((check) => typeof check !== "string")) {
|
|
1233
|
+
errors.push({
|
|
1234
|
+
path: "readiness.failedChecks",
|
|
1235
|
+
message: "readiness.failedChecks must be an array of strings."
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
function validateEvidence(evidence, errors) {
|
|
1240
|
+
if (!isRecord5(evidence)) {
|
|
1241
|
+
errors.push({
|
|
1242
|
+
path: "evidence",
|
|
1243
|
+
message: "evidence must be an object."
|
|
1244
|
+
});
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
if (!isRecord5(evidence.catalog)) {
|
|
1248
|
+
errors.push({
|
|
1249
|
+
path: "evidence.catalog",
|
|
1250
|
+
message: "evidence.catalog must be an object."
|
|
1251
|
+
});
|
|
1252
|
+
} else {
|
|
1253
|
+
validateNonEmptyString5(
|
|
1254
|
+
evidence.catalog.artifactId,
|
|
1255
|
+
"evidence.catalog.artifactId",
|
|
1256
|
+
errors
|
|
1257
|
+
);
|
|
1258
|
+
if (evidence.catalog.status !== "ready" && evidence.catalog.status !== "rejected") {
|
|
1259
|
+
errors.push({
|
|
1260
|
+
path: "evidence.catalog.status",
|
|
1261
|
+
message: 'evidence.catalog.status must be "ready" or "rejected".'
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
if (typeof evidence.catalog.accepted !== "boolean") {
|
|
1265
|
+
errors.push({
|
|
1266
|
+
path: "evidence.catalog.accepted",
|
|
1267
|
+
message: "evidence.catalog.accepted must be a boolean."
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
if (!isRecord5(evidence.conformance)) {
|
|
1272
|
+
errors.push({
|
|
1273
|
+
path: "evidence.conformance",
|
|
1274
|
+
message: "evidence.conformance must be an object."
|
|
1275
|
+
});
|
|
1276
|
+
} else {
|
|
1277
|
+
validateNonEmptyString5(
|
|
1278
|
+
evidence.conformance.artifactId,
|
|
1279
|
+
"evidence.conformance.artifactId",
|
|
1280
|
+
errors
|
|
1281
|
+
);
|
|
1282
|
+
if (evidence.conformance.status !== "verified" && evidence.conformance.status !== "failed") {
|
|
1283
|
+
errors.push({
|
|
1284
|
+
path: "evidence.conformance.status",
|
|
1285
|
+
message: 'evidence.conformance.status must be "verified" or "failed".'
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
if (!isRecord5(evidence.receipts)) {
|
|
1290
|
+
errors.push({
|
|
1291
|
+
path: "evidence.receipts",
|
|
1292
|
+
message: "evidence.receipts must be an object."
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
if (!Array.isArray(evidence.timelineEventTypes) || evidence.timelineEventTypes.some((type) => typeof type !== "string")) {
|
|
1296
|
+
errors.push({
|
|
1297
|
+
path: "evidence.timelineEventTypes",
|
|
1298
|
+
message: "evidence.timelineEventTypes must be an array of strings."
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
if (!Array.isArray(evidence.telemetryEventTypes) || evidence.telemetryEventTypes.some((type) => typeof type !== "string")) {
|
|
1302
|
+
errors.push({
|
|
1303
|
+
path: "evidence.telemetryEventTypes",
|
|
1304
|
+
message: "evidence.telemetryEventTypes must be an array of strings."
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
function validateNestedArtifacts(artifacts, errors) {
|
|
1309
|
+
if (!isRecord5(artifacts)) {
|
|
1310
|
+
errors.push({
|
|
1311
|
+
path: "artifacts",
|
|
1312
|
+
message: "artifacts must be an object."
|
|
1313
|
+
});
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
const catalogValidation = validateProviderCatalogArtifact(artifacts.catalog);
|
|
1317
|
+
for (const error of catalogValidation.errors) {
|
|
1318
|
+
errors.push({
|
|
1319
|
+
path: `artifacts.catalog.${error.path}`,
|
|
1320
|
+
message: error.message
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
const conformanceValidation = validateProviderConformanceArtifact(
|
|
1324
|
+
artifacts.conformance
|
|
1325
|
+
);
|
|
1326
|
+
for (const error of conformanceValidation.errors) {
|
|
1327
|
+
errors.push({
|
|
1328
|
+
path: `artifacts.conformance.${error.path}`,
|
|
1329
|
+
message: error.message
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
if (isRecord5(artifacts.catalog) && isRecord5(artifacts.conformance) && isRecord5(artifacts.catalog.provider) && isRecord5(artifacts.conformance.provider) && artifacts.catalog.provider.id !== artifacts.conformance.provider.id) {
|
|
1333
|
+
errors.push({
|
|
1334
|
+
path: "artifacts",
|
|
1335
|
+
message: "catalog and conformance artifacts must reference the same provider id."
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
function validateHashes2(dossier, errors) {
|
|
1340
|
+
if (!isRecord5(dossier.hashes)) {
|
|
1341
|
+
errors.push({
|
|
1342
|
+
path: "hashes",
|
|
1343
|
+
message: "hashes must be an object."
|
|
1344
|
+
});
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
for (const field of [
|
|
1348
|
+
"catalogArtifact",
|
|
1349
|
+
"conformanceArtifact",
|
|
1350
|
+
"readiness",
|
|
1351
|
+
"dossier"
|
|
1352
|
+
]) {
|
|
1353
|
+
const value = dossier.hashes[field];
|
|
1354
|
+
if (typeof value !== "string" || !/^[a-f0-9]{64}$/.test(value)) {
|
|
1355
|
+
errors.push({
|
|
1356
|
+
path: `hashes.${field}`,
|
|
1357
|
+
message: `${field} hash must be a sha256 hex string.`
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
if (!isRecord5(dossier.artifacts) || !isRecord5(dossier.readiness) || errors.some((error) => error.path.startsWith("hashes."))) {
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
const expectedHashes = {
|
|
1365
|
+
catalogArtifact: hashStableJson(dossier.artifacts.catalog),
|
|
1366
|
+
conformanceArtifact: hashStableJson(dossier.artifacts.conformance),
|
|
1367
|
+
readiness: hashStableJson(dossier.readiness),
|
|
1368
|
+
dossier: ""
|
|
1369
|
+
};
|
|
1370
|
+
const expectedDossierHash = hashDossierContent({
|
|
1371
|
+
...dossier,
|
|
1372
|
+
hashes: expectedHashes
|
|
1373
|
+
});
|
|
1374
|
+
for (const [field, expected] of Object.entries({
|
|
1375
|
+
...expectedHashes,
|
|
1376
|
+
dossier: expectedDossierHash
|
|
1377
|
+
})) {
|
|
1378
|
+
if (dossier.hashes[field] !== expected) {
|
|
1379
|
+
errors.push({
|
|
1380
|
+
path: `hashes.${field}`,
|
|
1381
|
+
message: `${field} hash does not match dossier content.`
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
function sanitizeDossierOutput(value, forbiddenOutputValues) {
|
|
1387
|
+
const forbiddenValues = forbiddenOutputValues.filter((entry) => entry.length > 0);
|
|
1388
|
+
return redactX402Secrets(
|
|
1389
|
+
replaceForbiddenValues(value, forbiddenValues, /* @__PURE__ */ new WeakSet())
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
function replaceForbiddenValues(value, forbiddenValues, seen) {
|
|
1393
|
+
if (typeof value === "string") {
|
|
1394
|
+
return forbiddenValues.reduce(
|
|
1395
|
+
(current, forbidden) => current.split(forbidden).join("[REDACTED]"),
|
|
1396
|
+
value
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
if (value === null || typeof value !== "object" || value instanceof Date) {
|
|
1400
|
+
return value;
|
|
1401
|
+
}
|
|
1402
|
+
if (seen.has(value)) {
|
|
1403
|
+
return "[Circular]";
|
|
1404
|
+
}
|
|
1405
|
+
seen.add(value);
|
|
1406
|
+
if (Array.isArray(value)) {
|
|
1407
|
+
const entries2 = value.map(
|
|
1408
|
+
(entry) => replaceForbiddenValues(entry, forbiddenValues, seen)
|
|
1409
|
+
);
|
|
1410
|
+
seen.delete(value);
|
|
1411
|
+
return entries2;
|
|
1412
|
+
}
|
|
1413
|
+
const entries = Object.fromEntries(
|
|
1414
|
+
Object.entries(value).map(([key, entry]) => [
|
|
1415
|
+
key,
|
|
1416
|
+
replaceForbiddenValues(entry, forbiddenValues, seen)
|
|
1417
|
+
])
|
|
1418
|
+
);
|
|
1419
|
+
seen.delete(value);
|
|
1420
|
+
return entries;
|
|
1421
|
+
}
|
|
1422
|
+
function cloneSerializable(value) {
|
|
1423
|
+
if (value === void 0) {
|
|
1424
|
+
return value;
|
|
1425
|
+
}
|
|
1426
|
+
return JSON.parse(JSON.stringify(value));
|
|
1427
|
+
}
|
|
1428
|
+
function hashStableJson(value) {
|
|
1429
|
+
return (0, import_node_crypto2.createHash)("sha256").update(stableStringify(value)).digest("hex");
|
|
1430
|
+
}
|
|
1431
|
+
function hashDossierContent(dossier) {
|
|
1432
|
+
return hashStableJson(dossier);
|
|
1433
|
+
}
|
|
1434
|
+
function stableStringify(value) {
|
|
1435
|
+
if (value === null || typeof value !== "object") {
|
|
1436
|
+
return JSON.stringify(value);
|
|
1437
|
+
}
|
|
1438
|
+
if (Array.isArray(value)) {
|
|
1439
|
+
return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
1440
|
+
}
|
|
1441
|
+
const entries = Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([left], [right]) => left.localeCompare(right));
|
|
1442
|
+
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(",")}}`;
|
|
1443
|
+
}
|
|
1444
|
+
function uniqueStrings(values) {
|
|
1445
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
1446
|
+
}
|
|
1447
|
+
function formatInlineList(values) {
|
|
1448
|
+
return values.length > 0 ? values.join(", ") : "none";
|
|
1449
|
+
}
|
|
1450
|
+
function isRecord5(value) {
|
|
1451
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1452
|
+
}
|
|
1453
|
+
function validateNonEmptyString5(value, path, errors) {
|
|
1454
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
1455
|
+
errors.push({
|
|
1456
|
+
path,
|
|
1457
|
+
message: `${path} must be a non-empty string.`
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
function validateIsoTimestamp3(value, path, errors) {
|
|
1462
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {
|
|
1463
|
+
errors.push({
|
|
1464
|
+
path,
|
|
1465
|
+
message: `${path} must be an ISO timestamp.`
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
function formatValidationErrors3(errors) {
|
|
1470
|
+
return errors.map((error) => `${error.path}: ${error.message}`).join("; ");
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// src/cli/providerOnboardingDossierCli.ts
|
|
1474
|
+
var USAGE = "Usage: probemesh-dossier --config <path> [--format markdown|json] [--out-json <path>] [--out-md <path>] [--dossier-id <text>] [--generated-at <iso>] [--title <text>]";
|
|
1475
|
+
async function runProviderOnboardingDossierCli(options = {}) {
|
|
1476
|
+
const argv = options.argv ?? [];
|
|
1477
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1478
|
+
try {
|
|
1479
|
+
const parsedArgs = parseCliArgs(argv);
|
|
1480
|
+
if (parsedArgs.help) {
|
|
1481
|
+
return {
|
|
1482
|
+
exitCode: 0,
|
|
1483
|
+
skipped: true,
|
|
1484
|
+
stdout: `${USAGE}
|
|
1485
|
+
`
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
if (!parsedArgs.configPath) {
|
|
1489
|
+
return cliFailure("--config <path> is required.");
|
|
1490
|
+
}
|
|
1491
|
+
const configExport = await loadCliConfig(parsedArgs.configPath, {
|
|
1492
|
+
argv,
|
|
1493
|
+
cwd
|
|
1494
|
+
});
|
|
1495
|
+
if (isCliSkip(configExport)) {
|
|
1496
|
+
return {
|
|
1497
|
+
exitCode: 0,
|
|
1498
|
+
skipped: true,
|
|
1499
|
+
skip: configExport,
|
|
1500
|
+
stdout: `provider onboarding dossier skipped: ${configExport.reason}
|
|
1501
|
+
`
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
assertCliConfig(configExport);
|
|
1505
|
+
const catalogArtifact = await resolveCatalogArtifact(configExport, cwd);
|
|
1506
|
+
const conformanceArtifact = await resolveConformanceArtifact(
|
|
1507
|
+
configExport,
|
|
1508
|
+
cwd
|
|
1509
|
+
);
|
|
1510
|
+
const dossier = createProviderOnboardingDossier({
|
|
1511
|
+
catalogArtifact,
|
|
1512
|
+
conformanceArtifact,
|
|
1513
|
+
dossierId: parsedArgs.dossierId ?? configExport.dossier?.dossierId,
|
|
1514
|
+
generatedAt: parsedArgs.generatedAt ?? configExport.dossier?.generatedAt,
|
|
1515
|
+
forbiddenOutputValues: configExport.dossier?.forbiddenOutputValues
|
|
1516
|
+
});
|
|
1517
|
+
const selectedFormat = parsedArgs.format ?? configExport.dossier?.format ?? "markdown";
|
|
1518
|
+
const title = parsedArgs.title ?? configExport.dossier?.title;
|
|
1519
|
+
const stdout = formatProviderOnboardingDossier(dossier, {
|
|
1520
|
+
format: selectedFormat,
|
|
1521
|
+
title
|
|
1522
|
+
});
|
|
1523
|
+
const artifactPaths = await writeArtifacts({
|
|
1524
|
+
cwd,
|
|
1525
|
+
dossier,
|
|
1526
|
+
title,
|
|
1527
|
+
outputs: {
|
|
1528
|
+
json: parsedArgs.outJson ?? configExport.outputs?.json,
|
|
1529
|
+
markdown: parsedArgs.outMarkdown ?? configExport.outputs?.markdown
|
|
1530
|
+
}
|
|
1531
|
+
});
|
|
1532
|
+
return {
|
|
1533
|
+
exitCode: dossier.status === "ready" ? 0 : 1,
|
|
1534
|
+
skipped: false,
|
|
1535
|
+
dossier,
|
|
1536
|
+
stdout,
|
|
1537
|
+
artifactPaths
|
|
1538
|
+
};
|
|
1539
|
+
} catch (error) {
|
|
1540
|
+
return cliFailure(
|
|
1541
|
+
error instanceof Error ? error.message : "Unknown provider onboarding dossier CLI failure."
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
function parseCliArgs(argv) {
|
|
1546
|
+
const parsedArgs = {};
|
|
1547
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
1548
|
+
const arg = argv[index];
|
|
1549
|
+
if (arg === "--") {
|
|
1550
|
+
continue;
|
|
1551
|
+
}
|
|
1552
|
+
if (arg === "--help" || arg === "-h") {
|
|
1553
|
+
parsedArgs.help = true;
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1556
|
+
if (arg === "--config") {
|
|
1557
|
+
parsedArgs.configPath = requireValue(argv, index, arg);
|
|
1558
|
+
index += 1;
|
|
1559
|
+
continue;
|
|
1560
|
+
}
|
|
1561
|
+
if (arg === "--format") {
|
|
1562
|
+
const format = requireValue(argv, index, arg);
|
|
1563
|
+
if (format !== "markdown" && format !== "json") {
|
|
1564
|
+
throw new Error("--format must be markdown or json.");
|
|
1565
|
+
}
|
|
1566
|
+
parsedArgs.format = format;
|
|
1567
|
+
index += 1;
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
if (arg === "--out-json") {
|
|
1571
|
+
parsedArgs.outJson = requireValue(argv, index, arg);
|
|
1572
|
+
index += 1;
|
|
1573
|
+
continue;
|
|
1574
|
+
}
|
|
1575
|
+
if (arg === "--out-md") {
|
|
1576
|
+
parsedArgs.outMarkdown = requireValue(argv, index, arg);
|
|
1577
|
+
index += 1;
|
|
1578
|
+
continue;
|
|
1579
|
+
}
|
|
1580
|
+
if (arg === "--dossier-id") {
|
|
1581
|
+
parsedArgs.dossierId = requireValue(argv, index, arg);
|
|
1582
|
+
index += 1;
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
if (arg === "--generated-at") {
|
|
1586
|
+
parsedArgs.generatedAt = requireValue(argv, index, arg);
|
|
1587
|
+
index += 1;
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
if (arg === "--title") {
|
|
1591
|
+
parsedArgs.title = requireValue(argv, index, arg);
|
|
1592
|
+
index += 1;
|
|
1593
|
+
continue;
|
|
1594
|
+
}
|
|
1595
|
+
throw new Error(`Unknown argument "${arg}".`);
|
|
1596
|
+
}
|
|
1597
|
+
return parsedArgs;
|
|
1598
|
+
}
|
|
1599
|
+
function requireValue(argv, index, flag) {
|
|
1600
|
+
const value = argv[index + 1];
|
|
1601
|
+
if (!value || value.startsWith("--")) {
|
|
1602
|
+
throw new Error(`${flag} requires a value.`);
|
|
1603
|
+
}
|
|
1604
|
+
return value;
|
|
1605
|
+
}
|
|
1606
|
+
async function loadCliConfig(configPath, context) {
|
|
1607
|
+
const configExport = await loadCliConfigDefault(configPath, context.cwd);
|
|
1608
|
+
if (typeof configExport === "function") {
|
|
1609
|
+
return configExport(context);
|
|
1610
|
+
}
|
|
1611
|
+
return configExport;
|
|
1612
|
+
}
|
|
1613
|
+
function isCliSkip(value) {
|
|
1614
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && value.skip === true && typeof value.reason === "string";
|
|
1615
|
+
}
|
|
1616
|
+
function assertCliConfig(config) {
|
|
1617
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
1618
|
+
throw new Error("Provider onboarding dossier CLI config must be an object.");
|
|
1619
|
+
}
|
|
1620
|
+
const candidate = config;
|
|
1621
|
+
if (candidate.catalogArtifact !== void 0 && candidate.catalogArtifactFile !== void 0) {
|
|
1622
|
+
throw new Error(
|
|
1623
|
+
"Provider onboarding dossier CLI config may not provide both catalogArtifact and catalogArtifactFile."
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
if (candidate.conformanceArtifact !== void 0 && candidate.conformanceArtifactFile !== void 0) {
|
|
1627
|
+
throw new Error(
|
|
1628
|
+
"Provider onboarding dossier CLI config may not provide both conformanceArtifact and conformanceArtifactFile."
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
if (candidate.catalogArtifact === void 0 && candidate.catalogArtifactFile === void 0) {
|
|
1632
|
+
throw new Error(
|
|
1633
|
+
"Provider onboarding dossier CLI config requires catalogArtifact or catalogArtifactFile."
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
if (candidate.conformanceArtifact === void 0 && candidate.conformanceArtifactFile === void 0) {
|
|
1637
|
+
throw new Error(
|
|
1638
|
+
"Provider onboarding dossier CLI config requires conformanceArtifact or conformanceArtifactFile."
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
if (candidate.catalogArtifactFile !== void 0 && typeof candidate.catalogArtifactFile !== "string") {
|
|
1642
|
+
throw new Error(
|
|
1643
|
+
"Provider onboarding dossier CLI catalogArtifactFile must be a string."
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
if (candidate.conformanceArtifactFile !== void 0 && typeof candidate.conformanceArtifactFile !== "string") {
|
|
1647
|
+
throw new Error(
|
|
1648
|
+
"Provider onboarding dossier CLI conformanceArtifactFile must be a string."
|
|
1649
|
+
);
|
|
1650
|
+
}
|
|
1651
|
+
if (candidate.dossier !== void 0 && !isRecord6(candidate.dossier)) {
|
|
1652
|
+
throw new Error("Provider onboarding dossier CLI dossier config must be an object.");
|
|
1653
|
+
}
|
|
1654
|
+
if (candidate.outputs !== void 0) {
|
|
1655
|
+
assertOutputs(candidate.outputs);
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
function assertOutputs(outputs) {
|
|
1659
|
+
if (!isRecord6(outputs)) {
|
|
1660
|
+
throw new Error("Provider onboarding dossier CLI outputs must be an object.");
|
|
1661
|
+
}
|
|
1662
|
+
for (const [key, value] of Object.entries(outputs)) {
|
|
1663
|
+
if (!["json", "markdown"].includes(key) || value !== void 0 && typeof value !== "string") {
|
|
1664
|
+
throw new Error(
|
|
1665
|
+
"Provider onboarding dossier CLI outputs may only include json and markdown string paths."
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
async function resolveCatalogArtifact(config, cwd) {
|
|
1671
|
+
if (config.catalogArtifact !== void 0) {
|
|
1672
|
+
assertProviderCatalogArtifact(config.catalogArtifact);
|
|
1673
|
+
return config.catalogArtifact;
|
|
1674
|
+
}
|
|
1675
|
+
const artifact = JSON.parse(
|
|
1676
|
+
await (0, import_promises2.readFile)((0, import_node_path2.resolve)(cwd, config.catalogArtifactFile), "utf8")
|
|
1677
|
+
);
|
|
1678
|
+
assertProviderCatalogArtifact(artifact);
|
|
1679
|
+
return artifact;
|
|
1680
|
+
}
|
|
1681
|
+
async function resolveConformanceArtifact(config, cwd) {
|
|
1682
|
+
if (config.conformanceArtifact !== void 0) {
|
|
1683
|
+
assertProviderConformanceArtifact(config.conformanceArtifact);
|
|
1684
|
+
return config.conformanceArtifact;
|
|
1685
|
+
}
|
|
1686
|
+
const artifact = JSON.parse(
|
|
1687
|
+
await (0, import_promises2.readFile)((0, import_node_path2.resolve)(cwd, config.conformanceArtifactFile), "utf8")
|
|
1688
|
+
);
|
|
1689
|
+
assertProviderConformanceArtifact(artifact);
|
|
1690
|
+
return artifact;
|
|
1691
|
+
}
|
|
1692
|
+
async function writeArtifacts(options) {
|
|
1693
|
+
const artifactPaths = {};
|
|
1694
|
+
if (options.outputs.json) {
|
|
1695
|
+
const path = (0, import_node_path2.resolve)(options.cwd, options.outputs.json);
|
|
1696
|
+
await writeTextFile(
|
|
1697
|
+
path,
|
|
1698
|
+
formatProviderOnboardingDossier(options.dossier, {
|
|
1699
|
+
format: "json",
|
|
1700
|
+
title: options.title
|
|
1701
|
+
})
|
|
1702
|
+
);
|
|
1703
|
+
artifactPaths.json = path;
|
|
1704
|
+
}
|
|
1705
|
+
if (options.outputs.markdown) {
|
|
1706
|
+
const path = (0, import_node_path2.resolve)(options.cwd, options.outputs.markdown);
|
|
1707
|
+
await writeTextFile(
|
|
1708
|
+
path,
|
|
1709
|
+
formatProviderOnboardingDossier(options.dossier, {
|
|
1710
|
+
format: "markdown",
|
|
1711
|
+
title: options.title
|
|
1712
|
+
})
|
|
1713
|
+
);
|
|
1714
|
+
artifactPaths.markdown = path;
|
|
1715
|
+
}
|
|
1716
|
+
return artifactPaths;
|
|
1717
|
+
}
|
|
1718
|
+
async function writeTextFile(path, body) {
|
|
1719
|
+
await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(path), {
|
|
1720
|
+
recursive: true
|
|
1721
|
+
});
|
|
1722
|
+
await (0, import_promises2.writeFile)(path, body, "utf8");
|
|
1723
|
+
}
|
|
1724
|
+
function cliFailure(message) {
|
|
1725
|
+
return {
|
|
1726
|
+
exitCode: 2,
|
|
1727
|
+
skipped: false,
|
|
1728
|
+
stdout: "",
|
|
1729
|
+
stderr: `Provider onboarding dossier CLI failed: ${message}
|
|
1730
|
+
${USAGE}
|
|
1731
|
+
`
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
function isRecord6(value) {
|
|
1735
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// src/cli/provider-dossier.ts
|
|
1739
|
+
void main();
|
|
1740
|
+
async function main() {
|
|
1741
|
+
const result = await runProviderOnboardingDossierCli({
|
|
1742
|
+
argv: process.argv.slice(2),
|
|
1743
|
+
cwd: process.cwd()
|
|
1744
|
+
});
|
|
1745
|
+
if (result.stdout) {
|
|
1746
|
+
process.stdout.write(result.stdout);
|
|
1747
|
+
}
|
|
1748
|
+
if (result.stderr) {
|
|
1749
|
+
process.stderr.write(result.stderr);
|
|
1750
|
+
}
|
|
1751
|
+
process.exitCode = result.exitCode;
|
|
1752
|
+
}
|
|
1753
|
+
//# sourceMappingURL=provider-dossier.cjs.map
|