@siglume/api-sdk 0.7.6 → 0.9.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/README.md +34 -3
- package/dist/bin/siglume.cjs +423 -36
- package/dist/bin/siglume.cjs.map +1 -1
- package/dist/bin/siglume.js +423 -36
- package/dist/bin/siglume.js.map +1 -1
- package/dist/cli/index.cjs +423 -36
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +11 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.js +423 -36
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +35 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +35 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/siglume.cjs
CHANGED
|
@@ -1351,6 +1351,9 @@ function parseListing(data) {
|
|
|
1351
1351
|
short_description: stringOrNull(data.short_description),
|
|
1352
1352
|
docs_url: stringOrNull(data.docs_url),
|
|
1353
1353
|
support_contact: stringOrNull(data.support_contact),
|
|
1354
|
+
seller_display_name: stringOrNull(data.seller_display_name),
|
|
1355
|
+
seller_homepage_url: stringOrNull(data.seller_homepage_url),
|
|
1356
|
+
seller_social_url: stringOrNull(data.seller_social_url),
|
|
1354
1357
|
review_status: stringOrNull(data.review_status),
|
|
1355
1358
|
review_note: stringOrNull(data.review_note),
|
|
1356
1359
|
submission_blockers: Array.isArray(data.submission_blockers) ? data.submission_blockers.filter((item) => typeof item === "string") : [],
|
|
@@ -2567,6 +2570,13 @@ var init_client = __esm({
|
|
|
2567
2570
|
if (options.runtime_validation) {
|
|
2568
2571
|
payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
|
|
2569
2572
|
}
|
|
2573
|
+
if (options.oauth_credentials) {
|
|
2574
|
+
payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
|
|
2575
|
+
items: options.oauth_credentials.map(
|
|
2576
|
+
(item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
|
|
2577
|
+
)
|
|
2578
|
+
} : coerceMapping(options.oauth_credentials, "oauth_credentials");
|
|
2579
|
+
}
|
|
2570
2580
|
if (options.metadata) {
|
|
2571
2581
|
payload.metadata = coerceMapping(options.metadata, "metadata");
|
|
2572
2582
|
}
|
|
@@ -2585,6 +2595,8 @@ var init_client = __esm({
|
|
|
2585
2595
|
"docs_url",
|
|
2586
2596
|
"documentation_url",
|
|
2587
2597
|
"support_contact",
|
|
2598
|
+
"seller_homepage_url",
|
|
2599
|
+
"seller_social_url",
|
|
2588
2600
|
"jurisdiction",
|
|
2589
2601
|
"price_model",
|
|
2590
2602
|
"price_value_minor",
|
|
@@ -2600,10 +2612,14 @@ var init_client = __esm({
|
|
|
2600
2612
|
}
|
|
2601
2613
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
2602
2614
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
2603
|
-
|
|
2615
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
2616
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
2617
|
+
if (docsUrl || supportContact || sellerHomepageUrl || sellerSocialUrl) {
|
|
2604
2618
|
const publisherIdentity = {
|
|
2605
2619
|
documentation_url: docsUrl || null,
|
|
2606
|
-
support_contact: supportContact || null
|
|
2620
|
+
support_contact: supportContact || null,
|
|
2621
|
+
seller_homepage_url: sellerHomepageUrl || null,
|
|
2622
|
+
seller_social_url: sellerSocialUrl || null
|
|
2607
2623
|
};
|
|
2608
2624
|
payload.publisher_identity = publisherIdentity;
|
|
2609
2625
|
payload.legal = { publisher_identity: publisherIdentity };
|
|
@@ -2617,36 +2633,39 @@ var init_client = __esm({
|
|
|
2617
2633
|
return {
|
|
2618
2634
|
listing_id,
|
|
2619
2635
|
status: String(data.status ?? "draft"),
|
|
2636
|
+
registration_mode: stringOrNull(data.registration_mode),
|
|
2637
|
+
listing_status: stringOrNull(data.listing_status),
|
|
2620
2638
|
auto_manifest: toRecord(data.auto_manifest),
|
|
2621
2639
|
confidence: toRecord(data.confidence),
|
|
2622
2640
|
validation_report: toRecord(data.validation_report),
|
|
2641
|
+
oauth_status: toRecord(data.oauth_status),
|
|
2623
2642
|
review_url: stringOrNull(data.review_url),
|
|
2624
2643
|
trace_id: meta.trace_id,
|
|
2625
2644
|
request_id: meta.request_id
|
|
2626
2645
|
};
|
|
2627
2646
|
}
|
|
2628
2647
|
async confirm_registration(listing_id, options = {}) {
|
|
2629
|
-
const
|
|
2630
|
-
const manifestPayload = options.manifest ? coerceMapping(options.manifest, "manifest") : pending?.manifest ?? {};
|
|
2631
|
-
const toolManualPayload = options.tool_manual ? coerceMapping(options.tool_manual, "tool_manual") : pending?.tool_manual ?? {};
|
|
2632
|
-
const overrides = {};
|
|
2633
|
-
for (const fieldName of ["name", "job_to_be_done"]) {
|
|
2634
|
-
if (manifestPayload[fieldName]) {
|
|
2635
|
-
overrides[fieldName] = manifestPayload[fieldName];
|
|
2636
|
-
}
|
|
2637
|
-
}
|
|
2638
|
-
if (Object.keys(toolManualPayload).length > 0) {
|
|
2639
|
-
overrides.tool_manual = toolManualPayload;
|
|
2640
|
-
}
|
|
2648
|
+
const { version_bump: versionBump } = options;
|
|
2641
2649
|
const payload = { approved: true };
|
|
2642
|
-
if (
|
|
2643
|
-
|
|
2650
|
+
if (versionBump !== void 0) {
|
|
2651
|
+
const allowed = ["patch", "minor", "major"];
|
|
2652
|
+
if (!allowed.includes(versionBump)) {
|
|
2653
|
+
throw new Error(
|
|
2654
|
+
`version_bump must be one of ${JSON.stringify(allowed)}, got ${JSON.stringify(versionBump)}`
|
|
2655
|
+
);
|
|
2656
|
+
}
|
|
2657
|
+
payload.version_bump = versionBump;
|
|
2644
2658
|
}
|
|
2645
2659
|
const [data, meta] = await this.request("POST", `/market/capabilities/${listing_id}/confirm-auto-register`, { json_body: payload });
|
|
2646
2660
|
this.pendingConfirmations.delete(listing_id);
|
|
2661
|
+
const checklist = isRecord(data.checklist) ? Object.fromEntries(
|
|
2662
|
+
Object.entries(data.checklist).map(([key, value]) => [key, Boolean(value)])
|
|
2663
|
+
) : {};
|
|
2647
2664
|
return {
|
|
2648
2665
|
listing_id: String(data.listing_id ?? listing_id),
|
|
2649
2666
|
status: String(data.status ?? ""),
|
|
2667
|
+
message: stringOrNull(data.message),
|
|
2668
|
+
checklist,
|
|
2650
2669
|
release: toRecord(data.release),
|
|
2651
2670
|
quality: parseRegistrationQuality(toRecord(data.quality)),
|
|
2652
2671
|
trace_id: meta.trace_id,
|
|
@@ -7166,6 +7185,15 @@ async function loadProject(path = ".") {
|
|
|
7166
7185
|
const tool_manual = tool_manual_path ? JSON.parse(await (0, import_promises.readFile)(tool_manual_path, "utf8")) : buildToolManualTemplate(manifest);
|
|
7167
7186
|
const runtime_validation_path = await findRuntimeValidationPath(root_dir);
|
|
7168
7187
|
const runtime_validation = runtime_validation_path ? await loadJsonObject(runtime_validation_path, "runtime_validation") : void 0;
|
|
7188
|
+
const oauth_credentials_path = await findOauthCredentialsPath(root_dir);
|
|
7189
|
+
let oauth_credentials;
|
|
7190
|
+
if (oauth_credentials_path) {
|
|
7191
|
+
const parsed = JSON.parse(await (0, import_promises.readFile)(oauth_credentials_path, "utf8"));
|
|
7192
|
+
if (!isRecord(parsed) && !Array.isArray(parsed)) {
|
|
7193
|
+
throw new SiglumeProjectError("oauth_credentials must be a JSON object or array");
|
|
7194
|
+
}
|
|
7195
|
+
oauth_credentials = parsed;
|
|
7196
|
+
}
|
|
7169
7197
|
return {
|
|
7170
7198
|
root_dir,
|
|
7171
7199
|
adapter_path,
|
|
@@ -7174,9 +7202,110 @@ async function loadProject(path = ".") {
|
|
|
7174
7202
|
tool_manual_path: tool_manual_path ?? void 0,
|
|
7175
7203
|
tool_manual,
|
|
7176
7204
|
runtime_validation_path: runtime_validation_path ?? void 0,
|
|
7177
|
-
runtime_validation
|
|
7205
|
+
runtime_validation,
|
|
7206
|
+
oauth_credentials_path: oauth_credentials_path ?? void 0,
|
|
7207
|
+
oauth_credentials
|
|
7178
7208
|
};
|
|
7179
7209
|
}
|
|
7210
|
+
var OAUTH_PROVIDER_ALIASES = {
|
|
7211
|
+
x: "twitter",
|
|
7212
|
+
"x-twitter": "twitter",
|
|
7213
|
+
twitter: "twitter",
|
|
7214
|
+
slack: "slack",
|
|
7215
|
+
google: "google",
|
|
7216
|
+
gmail: "google",
|
|
7217
|
+
"google-drive": "google",
|
|
7218
|
+
"google-calendar": "google",
|
|
7219
|
+
github: "github",
|
|
7220
|
+
linear: "linear",
|
|
7221
|
+
notion: "notion"
|
|
7222
|
+
};
|
|
7223
|
+
function oauthProviderKeyFromRequirement(value) {
|
|
7224
|
+
const raw = String(value ?? "").trim().toLowerCase().replaceAll("_", "-");
|
|
7225
|
+
if (!raw) return null;
|
|
7226
|
+
if (OAUTH_PROVIDER_ALIASES[raw]) {
|
|
7227
|
+
return OAUTH_PROVIDER_ALIASES[raw];
|
|
7228
|
+
}
|
|
7229
|
+
for (const token of raw.replaceAll("/", "-").replaceAll(":", "-").split("-")) {
|
|
7230
|
+
const next = token.trim();
|
|
7231
|
+
if (OAUTH_PROVIDER_ALIASES[next]) {
|
|
7232
|
+
return OAUTH_PROVIDER_ALIASES[next];
|
|
7233
|
+
}
|
|
7234
|
+
}
|
|
7235
|
+
return null;
|
|
7236
|
+
}
|
|
7237
|
+
function requiredOauthProviders(requirements) {
|
|
7238
|
+
const providers = [];
|
|
7239
|
+
for (const item of requirements ?? []) {
|
|
7240
|
+
const providerKey = oauthProviderKeyFromRequirement(item);
|
|
7241
|
+
if (providerKey && !providers.includes(providerKey)) {
|
|
7242
|
+
providers.push(providerKey);
|
|
7243
|
+
}
|
|
7244
|
+
}
|
|
7245
|
+
return providers;
|
|
7246
|
+
}
|
|
7247
|
+
function oauthProviderRecordsMap(payload) {
|
|
7248
|
+
if (!payload) {
|
|
7249
|
+
return {};
|
|
7250
|
+
}
|
|
7251
|
+
const items = Array.isArray(payload) ? payload : Array.isArray(payload.items) ? payload.items : [payload];
|
|
7252
|
+
const resolved = {};
|
|
7253
|
+
for (const [index, item] of items.entries()) {
|
|
7254
|
+
if (!isRecord(item)) {
|
|
7255
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must be a JSON object.`);
|
|
7256
|
+
}
|
|
7257
|
+
const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
|
|
7258
|
+
if (!providerKey) {
|
|
7259
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is unsupported.`);
|
|
7260
|
+
}
|
|
7261
|
+
const clientId = String(item.client_id ?? "").trim();
|
|
7262
|
+
const clientSecret = String(item.client_secret ?? "").trim();
|
|
7263
|
+
if (!clientId || !clientSecret) {
|
|
7264
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must include client_id and client_secret.`);
|
|
7265
|
+
}
|
|
7266
|
+
const rawScopes = item.required_scopes ?? item.scopes;
|
|
7267
|
+
let scopes = [];
|
|
7268
|
+
if (rawScopes == null) {
|
|
7269
|
+
scopes = [];
|
|
7270
|
+
} else if (!Array.isArray(rawScopes)) {
|
|
7271
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].required_scopes must be a JSON array.`);
|
|
7272
|
+
} else {
|
|
7273
|
+
scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
|
|
7274
|
+
}
|
|
7275
|
+
resolved[providerKey] = {
|
|
7276
|
+
provider_key: providerKey,
|
|
7277
|
+
client_id: clientId,
|
|
7278
|
+
client_secret: clientSecret,
|
|
7279
|
+
required_scopes: scopes
|
|
7280
|
+
};
|
|
7281
|
+
}
|
|
7282
|
+
return resolved;
|
|
7283
|
+
}
|
|
7284
|
+
function canonicalOauthCredentialsPayload(payload) {
|
|
7285
|
+
const records = oauthProviderRecordsMap(payload);
|
|
7286
|
+
const providerKeys = Object.keys(records).sort();
|
|
7287
|
+
if (providerKeys.length === 0) {
|
|
7288
|
+
return void 0;
|
|
7289
|
+
}
|
|
7290
|
+
return {
|
|
7291
|
+
items: providerKeys.map((providerKey) => records[providerKey])
|
|
7292
|
+
};
|
|
7293
|
+
}
|
|
7294
|
+
function ensureRequiredOauthCredentials(project) {
|
|
7295
|
+
const requiredProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7296
|
+
if (requiredProviders.length === 0) {
|
|
7297
|
+
return;
|
|
7298
|
+
}
|
|
7299
|
+
const provided = new Set(Object.keys(oauthProviderRecordsMap(project.oauth_credentials)));
|
|
7300
|
+
const missing = requiredProviders.filter((provider) => !provided.has(provider));
|
|
7301
|
+
if (missing.length === 0) {
|
|
7302
|
+
return;
|
|
7303
|
+
}
|
|
7304
|
+
const path = project.oauth_credentials_path ?? (0, import_node_path.join)(project.root_dir, "oauth_credentials.json");
|
|
7305
|
+
throw new SiglumeProjectError(
|
|
7306
|
+
`${path} is required for OAuth-backed APIs. Missing provider seeds: ${missing.join(", ")}`
|
|
7307
|
+
);
|
|
7308
|
+
}
|
|
7180
7309
|
async function validateProject(path = ".", deps = {}) {
|
|
7181
7310
|
const project = await loadProject(path);
|
|
7182
7311
|
const manifest_issues = await projectValidationIssues(project);
|
|
@@ -7213,17 +7342,31 @@ function ensureManifestPublisherIdentity(project) {
|
|
|
7213
7342
|
const manifestPayload = project.manifest;
|
|
7214
7343
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
7215
7344
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
7345
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
7346
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
7216
7347
|
const jurisdiction = String(manifestPayload.jurisdiction ?? "").trim();
|
|
7217
7348
|
const issues = [];
|
|
7218
7349
|
if (!docsUrl) {
|
|
7219
7350
|
issues.push("manifest.docs_url is required");
|
|
7220
7351
|
} else if (looksLikePlaceholder(docsUrl)) {
|
|
7221
7352
|
issues.push("manifest.docs_url must be replaced with your public documentation URL");
|
|
7353
|
+
} else if (!looksLikeHttpUrl(docsUrl)) {
|
|
7354
|
+
issues.push("manifest.docs_url must be an http(s) URL");
|
|
7355
|
+
} else if (looksLikeRootUrl(docsUrl)) {
|
|
7356
|
+
issues.push("manifest.docs_url must be a dedicated API usage page, not a root homepage URL");
|
|
7222
7357
|
}
|
|
7223
7358
|
if (!supportContact) {
|
|
7224
7359
|
issues.push("manifest.support_contact is required");
|
|
7225
7360
|
} else if (looksLikePlaceholder(supportContact)) {
|
|
7226
7361
|
issues.push("manifest.support_contact must be replaced with your real support email or support URL");
|
|
7362
|
+
} else if (!looksLikeEmail(supportContact) && !looksLikeHttpUrl(supportContact)) {
|
|
7363
|
+
issues.push("manifest.support_contact must be a real email address or http(s) support URL");
|
|
7364
|
+
}
|
|
7365
|
+
if (sellerHomepageUrl && (looksLikePlaceholder(sellerHomepageUrl) || !looksLikeHttpUrl(sellerHomepageUrl))) {
|
|
7366
|
+
issues.push("manifest.seller_homepage_url must be a real http(s) official homepage URL when provided");
|
|
7367
|
+
}
|
|
7368
|
+
if (sellerSocialUrl && (looksLikePlaceholder(sellerSocialUrl) || !looksLikeHttpUrl(sellerSocialUrl))) {
|
|
7369
|
+
issues.push("manifest.seller_social_url must be a real http(s) official social/profile URL when provided");
|
|
7227
7370
|
}
|
|
7228
7371
|
if (!jurisdiction) issues.push("manifest.jurisdiction is required");
|
|
7229
7372
|
if (issues.length > 0) {
|
|
@@ -7235,7 +7378,25 @@ ${issues.map((issue2) => `- ${issue2}`).join("\n")}`
|
|
|
7235
7378
|
}
|
|
7236
7379
|
function looksLikePlaceholder(value) {
|
|
7237
7380
|
const normalized = value.trim().toLowerCase();
|
|
7238
|
-
return !normalized || normalized.includes("example.com") || normalized.startsWith("replace-with-") || normalized.startsWith("your-") || normalized.includes("your-domain") || normalized.includes("localhost") || normalized.includes("127.0.0.1") || normalized.includes("0.0.0.0");
|
|
7381
|
+
return !normalized || normalized.includes("example.com") || normalized.includes("example.net") || normalized.includes("example.org") || normalized.startsWith("replace-with-") || normalized.startsWith("your-") || normalized.includes("your-domain") || normalized.includes("localhost") || normalized.includes("127.0.0.1") || normalized.includes("0.0.0.0");
|
|
7382
|
+
}
|
|
7383
|
+
function looksLikeHttpUrl(value) {
|
|
7384
|
+
try {
|
|
7385
|
+
const parsed = new URL(value.trim());
|
|
7386
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
7387
|
+
} catch {
|
|
7388
|
+
return false;
|
|
7389
|
+
}
|
|
7390
|
+
}
|
|
7391
|
+
function looksLikeRootUrl(value) {
|
|
7392
|
+
if (!looksLikeHttpUrl(value)) return false;
|
|
7393
|
+
const parsed = new URL(value.trim());
|
|
7394
|
+
return parsed.pathname.replace(/^\/+|\/+$/g, "") === "";
|
|
7395
|
+
}
|
|
7396
|
+
function looksLikeEmail(value) {
|
|
7397
|
+
const normalized = value.trim();
|
|
7398
|
+
const domain = normalized.split("@").at(-1) ?? "";
|
|
7399
|
+
return normalized.includes("@") && !normalized.includes(" ") && domain.includes(".") && !normalized.startsWith("@");
|
|
7239
7400
|
}
|
|
7240
7401
|
function runtimePlaceholderIssues(runtimeValidation) {
|
|
7241
7402
|
const issues = [];
|
|
@@ -7295,6 +7456,9 @@ async function registrationPreflight(project, client) {
|
|
|
7295
7456
|
const manifestIssues = await projectValidationIssues(project);
|
|
7296
7457
|
const [toolManualValid, toolManualIssues] = validate_tool_manual(project.tool_manual);
|
|
7297
7458
|
const remoteQuality = await client.preview_quality_score(project.tool_manual);
|
|
7459
|
+
const requiredOauthProvidersList = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7460
|
+
const oauthProviderRecords = oauthProviderRecordsMap(project.oauth_credentials);
|
|
7461
|
+
const missingOauthProviders = requiredOauthProvidersList.filter((provider) => !oauthProviderRecords[provider]);
|
|
7298
7462
|
const blockingToolManualIssues = toolManualIssues.filter((issue2) => issue2.severity === "error");
|
|
7299
7463
|
const errors = [
|
|
7300
7464
|
...manifestIssues.map((issue2) => String(issue2)),
|
|
@@ -7306,11 +7470,17 @@ async function registrationPreflight(project, client) {
|
|
|
7306
7470
|
if (!remoteQualityOk(remoteQuality)) {
|
|
7307
7471
|
errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
|
|
7308
7472
|
}
|
|
7473
|
+
if (missingOauthProviders.length > 0) {
|
|
7474
|
+
errors.push(`oauth_credentials.json is required for OAuth-backed APIs: ${missingOauthProviders.join(", ")}`);
|
|
7475
|
+
}
|
|
7309
7476
|
const preflight = {
|
|
7310
7477
|
manifest_issues: manifestIssues,
|
|
7311
7478
|
tool_manual_valid: toolManualValid,
|
|
7312
7479
|
tool_manual_issues: toolManualIssues.map((issue2) => toJsonable(issue2)),
|
|
7313
7480
|
remote_quality: toJsonable(remoteQuality),
|
|
7481
|
+
required_oauth_providers: requiredOauthProvidersList,
|
|
7482
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null,
|
|
7483
|
+
oauth_missing_providers: missingOauthProviders,
|
|
7314
7484
|
ok: errors.length === 0
|
|
7315
7485
|
};
|
|
7316
7486
|
if (errors.length > 0) {
|
|
@@ -7326,6 +7496,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7326
7496
|
ensureExplicitToolManual(project);
|
|
7327
7497
|
ensureManifestPublisherIdentity(project);
|
|
7328
7498
|
ensureRuntimeValidationReady(project);
|
|
7499
|
+
ensureRequiredOauthCredentials(project);
|
|
7329
7500
|
const client = await createClient(deps);
|
|
7330
7501
|
const preflight = await registrationPreflight(project, client);
|
|
7331
7502
|
let developerPortalPreflight = null;
|
|
@@ -7334,18 +7505,20 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7334
7505
|
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7335
7506
|
if (verifiedDestination !== true) {
|
|
7336
7507
|
throw new SiglumeProjectError(
|
|
7337
|
-
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/
|
|
7508
|
+
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/credits/payout and confirm the embedded-wallet payout token, or call GET /v1/market/developer/portal until payout_readiness.verified_destination is true."
|
|
7338
7509
|
);
|
|
7339
7510
|
}
|
|
7340
7511
|
developerPortalPreflight = toJsonable(portal);
|
|
7341
7512
|
}
|
|
7342
7513
|
const receipt = await client.auto_register(project.manifest, project.tool_manual, {
|
|
7343
|
-
runtime_validation: project.runtime_validation
|
|
7514
|
+
runtime_validation: project.runtime_validation,
|
|
7515
|
+
oauth_credentials: canonicalOauthCredentialsPayload(project.oauth_credentials)
|
|
7344
7516
|
});
|
|
7345
7517
|
const result = {
|
|
7346
7518
|
receipt: toJsonable(receipt),
|
|
7347
7519
|
registration_preflight: preflight,
|
|
7348
|
-
runtime_validation_path: project.runtime_validation_path ?? null
|
|
7520
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7521
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7349
7522
|
};
|
|
7350
7523
|
if (developerPortalPreflight) {
|
|
7351
7524
|
result.developer_portal_preflight = developerPortalPreflight;
|
|
@@ -7360,6 +7533,37 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7360
7533
|
}
|
|
7361
7534
|
return result;
|
|
7362
7535
|
}
|
|
7536
|
+
async function runPreflight(path = ".", deps = {}) {
|
|
7537
|
+
const project = await loadProject(path);
|
|
7538
|
+
ensureExplicitToolManual(project);
|
|
7539
|
+
ensureManifestPublisherIdentity(project);
|
|
7540
|
+
ensureRuntimeValidationReady(project);
|
|
7541
|
+
ensureRequiredOauthCredentials(project);
|
|
7542
|
+
const client = await createClient(deps);
|
|
7543
|
+
const preflight = await registrationPreflight(project, client);
|
|
7544
|
+
let developerPortalPreflight = null;
|
|
7545
|
+
if (String(project.manifest.price_model ?? "free").toLowerCase() !== "free") {
|
|
7546
|
+
const portal = await client.get_developer_portal();
|
|
7547
|
+
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7548
|
+
if (verifiedDestination !== true) {
|
|
7549
|
+
throw new SiglumeProjectError(
|
|
7550
|
+
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/credits/payout and confirm the embedded-wallet payout token, or call GET /v1/market/developer/portal until payout_readiness.verified_destination is true."
|
|
7551
|
+
);
|
|
7552
|
+
}
|
|
7553
|
+
developerPortalPreflight = toJsonable(portal);
|
|
7554
|
+
}
|
|
7555
|
+
const result = {
|
|
7556
|
+
ok: true,
|
|
7557
|
+
adapter_path: project.adapter_path,
|
|
7558
|
+
registration_preflight: preflight,
|
|
7559
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7560
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7561
|
+
};
|
|
7562
|
+
if (developerPortalPreflight) {
|
|
7563
|
+
result.developer_portal_preflight = developerPortalPreflight;
|
|
7564
|
+
}
|
|
7565
|
+
return result;
|
|
7566
|
+
}
|
|
7363
7567
|
async function createSupportCaseReport(options, deps = {}) {
|
|
7364
7568
|
const client = await createClient(deps);
|
|
7365
7569
|
const supportCase = await client.create_support_case(options.subject, options.body, { trace_id: options.trace_id });
|
|
@@ -7406,8 +7610,12 @@ async function writeInitTemplate(template, destination) {
|
|
|
7406
7610
|
const manifest_path = (0, import_node_path.join)(root, "manifest.json");
|
|
7407
7611
|
const tool_manual_path = (0, import_node_path.join)(root, "tool_manual.json");
|
|
7408
7612
|
const runtime_validation_path = (0, import_node_path.join)(root, "runtime_validation.json");
|
|
7613
|
+
const gitignore_path = (0, import_node_path.join)(root, ".gitignore");
|
|
7409
7614
|
const readme_path = (0, import_node_path.join)(root, "README.md");
|
|
7410
|
-
|
|
7615
|
+
const docs_dir = (0, import_node_path.join)(root, "docs");
|
|
7616
|
+
await (0, import_promises.mkdir)(docs_dir, { recursive: true });
|
|
7617
|
+
const docs_usage_path = (0, import_node_path.join)(docs_dir, "api-usage.md");
|
|
7618
|
+
for (const filePath of [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, readme_path]) {
|
|
7411
7619
|
if ((0, import_node_fs.existsSync)(filePath)) {
|
|
7412
7620
|
throw new SiglumeProjectError(`${(0, import_node_path.basename)(filePath)} already exists in ${root}`);
|
|
7413
7621
|
}
|
|
@@ -7418,8 +7626,10 @@ async function writeInitTemplate(template, destination) {
|
|
|
7418
7626
|
await (0, import_promises.writeFile)(manifest_path, renderJson(manifest), "utf8");
|
|
7419
7627
|
await (0, import_promises.writeFile)(tool_manual_path, renderJson(toolManual), "utf8");
|
|
7420
7628
|
await (0, import_promises.writeFile)(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(toolManual)), "utf8");
|
|
7629
|
+
await (0, import_promises.writeFile)(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
7630
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7421
7631
|
await (0, import_promises.writeFile)(readme_path, readmeTemplate(template), "utf8");
|
|
7422
|
-
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, readme_path];
|
|
7632
|
+
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, gitignore_path, readme_path];
|
|
7423
7633
|
}
|
|
7424
7634
|
async function listOperationCatalog(options = {}, deps = {}) {
|
|
7425
7635
|
const resolvedAgentId = String(options.agent_id ?? "").trim();
|
|
@@ -7813,12 +8023,19 @@ function operationReadmeTemplate(operation, manifest, warning) {
|
|
|
7813
8023
|
"- `stubs.ts`: mock fallback used when `SIGLUME_API_KEY` is not set",
|
|
7814
8024
|
"- `manifest.json`: reviewable manifest snapshot",
|
|
7815
8025
|
"- `tool_manual.json`: machine-generated ToolManual scaffold",
|
|
7816
|
-
"- `runtime_validation.json`: public endpoint and review-key checks used by auto-register",
|
|
8026
|
+
"- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
|
|
8027
|
+
"- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
|
|
8028
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
7817
8029
|
"- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
|
|
7818
8030
|
"",
|
|
7819
8031
|
"Before registering, replace all generated placeholders:",
|
|
7820
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
7821
|
-
"-
|
|
8032
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8033
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8034
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8035
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8036
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8037
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8038
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
7822
8039
|
"",
|
|
7823
8040
|
"## Commands",
|
|
7824
8041
|
"",
|
|
@@ -7830,16 +8047,108 @@ function operationReadmeTemplate(operation, manifest, warning) {
|
|
|
7830
8047
|
"siglume score . --offline",
|
|
7831
8048
|
"```",
|
|
7832
8049
|
"",
|
|
7833
|
-
"After placeholders are replaced and `SIGLUME_API_KEY` is
|
|
8050
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
7834
8051
|
"",
|
|
7835
8052
|
"```bash",
|
|
7836
8053
|
"siglume validate .",
|
|
7837
8054
|
"siglume score . --remote",
|
|
8055
|
+
"siglume preflight .",
|
|
8056
|
+
"siglume register .",
|
|
8057
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
7838
8058
|
"siglume register . --confirm",
|
|
7839
8059
|
"```",
|
|
7840
8060
|
""
|
|
7841
8061
|
].join("\n");
|
|
7842
8062
|
}
|
|
8063
|
+
function apiUsageDocsTemplate(manifest) {
|
|
8064
|
+
const name = String(manifest.name ?? manifest.capability_key ?? "Siglume API");
|
|
8065
|
+
const capabilityKey = String(manifest.capability_key ?? "replace-with-capability-key");
|
|
8066
|
+
const jobToBeDone = String(manifest.job_to_be_done ?? "Describe what this API lets an agent do.");
|
|
8067
|
+
const permissionClass = String(manifest.permission_class ?? "read-only");
|
|
8068
|
+
const priceModel = String(manifest.price_model ?? "free");
|
|
8069
|
+
const requiredAccounts = (manifest.required_connected_accounts ?? []).join(", ") || "none";
|
|
8070
|
+
const supportContact = String(manifest.support_contact ?? "replace-with-support-contact");
|
|
8071
|
+
return [
|
|
8072
|
+
`# ${name} API Usage Guide`,
|
|
8073
|
+
"",
|
|
8074
|
+
`This page is the dedicated public usage guide for the Siglume API listing \`${capabilityKey}\`.`,
|
|
8075
|
+
"Publish this page at an anonymous HTTP 200 URL and use that URL as `docs_url`.",
|
|
8076
|
+
"",
|
|
8077
|
+
"Do not use your company homepage as `docs_url`; keep seller/company homepages in `seller_homepage_url`.",
|
|
8078
|
+
"",
|
|
8079
|
+
"## What This API Does",
|
|
8080
|
+
"",
|
|
8081
|
+
jobToBeDone,
|
|
8082
|
+
"",
|
|
8083
|
+
"## Permission Model",
|
|
8084
|
+
"",
|
|
8085
|
+
`- Permission class: \`${permissionClass}\``,
|
|
8086
|
+
`- Price model: \`${priceModel}\``,
|
|
8087
|
+
`- Required connected accounts: \`${requiredAccounts}\``,
|
|
8088
|
+
"",
|
|
8089
|
+
"## Inputs",
|
|
8090
|
+
"",
|
|
8091
|
+
"Describe the request fields your API accepts. Keep this aligned with `tool_manual.json` and `runtime_validation.json`.",
|
|
8092
|
+
"",
|
|
8093
|
+
"## Outputs",
|
|
8094
|
+
"",
|
|
8095
|
+
"Describe the response fields your API returns. Include the fields in `runtime_validation.expected_response_fields`.",
|
|
8096
|
+
"",
|
|
8097
|
+
"## Errors And Support",
|
|
8098
|
+
"",
|
|
8099
|
+
"Explain common error messages and how an owner should recover.",
|
|
8100
|
+
"",
|
|
8101
|
+
`Support contact: ${supportContact}`,
|
|
8102
|
+
""
|
|
8103
|
+
].join("\n");
|
|
8104
|
+
}
|
|
8105
|
+
function generatedGitignore() {
|
|
8106
|
+
return [
|
|
8107
|
+
"# Local secrets and registration-only runtime checks.",
|
|
8108
|
+
".env",
|
|
8109
|
+
".env.*",
|
|
8110
|
+
"!.env.example",
|
|
8111
|
+
"runtime_validation.json",
|
|
8112
|
+
"runtime-validation.json",
|
|
8113
|
+
"oauth_credentials.json",
|
|
8114
|
+
"oauth-credentials.json",
|
|
8115
|
+
"",
|
|
8116
|
+
"# Python / test artifacts.",
|
|
8117
|
+
"__pycache__/",
|
|
8118
|
+
"*.py[cod]",
|
|
8119
|
+
".pytest_cache/",
|
|
8120
|
+
".mypy_cache/",
|
|
8121
|
+
".coverage",
|
|
8122
|
+
"htmlcov/",
|
|
8123
|
+
"dist/",
|
|
8124
|
+
"build/",
|
|
8125
|
+
"*.egg-info/",
|
|
8126
|
+
"",
|
|
8127
|
+
"# JavaScript tooling if this project also uses TypeScript helpers.",
|
|
8128
|
+
"node_modules/",
|
|
8129
|
+
"coverage/",
|
|
8130
|
+
""
|
|
8131
|
+
].join("\n");
|
|
8132
|
+
}
|
|
8133
|
+
async function writeOrMergeGitignore(filePath) {
|
|
8134
|
+
const generated = generatedGitignore();
|
|
8135
|
+
if (!(0, import_node_fs.existsSync)(filePath)) {
|
|
8136
|
+
await (0, import_promises.writeFile)(filePath, generated, "utf8");
|
|
8137
|
+
return;
|
|
8138
|
+
}
|
|
8139
|
+
const existing = await (0, import_promises.readFile)(filePath, "utf8");
|
|
8140
|
+
const existingEntries = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
|
|
8141
|
+
const additions = generated.split(/\r?\n/).filter((line) => line.trim() && !existingEntries.has(line.trim()));
|
|
8142
|
+
if (additions.length === 0) {
|
|
8143
|
+
return;
|
|
8144
|
+
}
|
|
8145
|
+
const prefix = existing.endsWith("\n") ? existing : `${existing}
|
|
8146
|
+
`;
|
|
8147
|
+
await (0, import_promises.writeFile)(filePath, `${prefix}
|
|
8148
|
+
# Siglume generated ignores.
|
|
8149
|
+
${additions.join("\n")}
|
|
8150
|
+
`, "utf8");
|
|
8151
|
+
}
|
|
7843
8152
|
async function writeOperationTemplate(operation_key, destination, options = {}, deps = {}) {
|
|
7844
8153
|
const root = (0, import_node_path.resolve)(destination);
|
|
7845
8154
|
await (0, import_promises.mkdir)(root, { recursive: true });
|
|
@@ -7850,9 +8159,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7850
8159
|
const manifest_path = (0, import_node_path.join)(root, "manifest.json");
|
|
7851
8160
|
const tool_manual_path = (0, import_node_path.join)(root, "tool_manual.json");
|
|
7852
8161
|
const runtime_validation_path = (0, import_node_path.join)(root, "runtime_validation.json");
|
|
8162
|
+
const gitignore_path = (0, import_node_path.join)(root, ".gitignore");
|
|
7853
8163
|
const readme_path = (0, import_node_path.join)(root, "README.md");
|
|
7854
8164
|
const test_path = (0, import_node_path.join)(testsDir, "test_adapter.ts");
|
|
7855
|
-
|
|
8165
|
+
const docs_dir = (0, import_node_path.join)(root, "docs");
|
|
8166
|
+
await (0, import_promises.mkdir)(docs_dir, { recursive: true });
|
|
8167
|
+
const docs_usage_path = (0, import_node_path.join)(docs_dir, "api-usage.md");
|
|
8168
|
+
for (const filePath of [
|
|
8169
|
+
adapter_path,
|
|
8170
|
+
stubs_path,
|
|
8171
|
+
manifest_path,
|
|
8172
|
+
tool_manual_path,
|
|
8173
|
+
runtime_validation_path,
|
|
8174
|
+
docs_usage_path,
|
|
8175
|
+
readme_path,
|
|
8176
|
+
test_path
|
|
8177
|
+
]) {
|
|
7856
8178
|
if ((0, import_node_fs.existsSync)(filePath)) {
|
|
7857
8179
|
throw new SiglumeProjectError(`${(0, import_node_path.basename)(filePath)} already exists in ${root}`);
|
|
7858
8180
|
}
|
|
@@ -7880,10 +8202,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7880
8202
|
await (0, import_promises.writeFile)(manifest_path, renderJson(manifest), "utf8");
|
|
7881
8203
|
await (0, import_promises.writeFile)(tool_manual_path, renderJson(tool_manual), "utf8");
|
|
7882
8204
|
await (0, import_promises.writeFile)(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(tool_manual)), "utf8");
|
|
8205
|
+
await (0, import_promises.writeFile)(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
8206
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7883
8207
|
await (0, import_promises.writeFile)(readme_path, operationReadmeTemplate(operation, manifest, warning), "utf8");
|
|
7884
8208
|
await (0, import_promises.writeFile)(test_path, operationTestSource(operation), "utf8");
|
|
7885
8209
|
return {
|
|
7886
|
-
files: [
|
|
8210
|
+
files: [
|
|
8211
|
+
adapter_path,
|
|
8212
|
+
stubs_path,
|
|
8213
|
+
manifest_path,
|
|
8214
|
+
tool_manual_path,
|
|
8215
|
+
runtime_validation_path,
|
|
8216
|
+
docs_usage_path,
|
|
8217
|
+
gitignore_path,
|
|
8218
|
+
readme_path,
|
|
8219
|
+
test_path
|
|
8220
|
+
],
|
|
7887
8221
|
operation,
|
|
7888
8222
|
report: {
|
|
7889
8223
|
tool_manual_valid,
|
|
@@ -8032,6 +8366,15 @@ async function findRuntimeValidationPath(root_dir) {
|
|
|
8032
8366
|
}
|
|
8033
8367
|
return null;
|
|
8034
8368
|
}
|
|
8369
|
+
async function findOauthCredentialsPath(root_dir) {
|
|
8370
|
+
for (const name of ["oauth_credentials.json", "oauth-credentials.json"]) {
|
|
8371
|
+
const candidate = (0, import_node_path.join)(root_dir, name);
|
|
8372
|
+
if ((0, import_node_fs.existsSync)(candidate)) {
|
|
8373
|
+
return candidate;
|
|
8374
|
+
}
|
|
8375
|
+
}
|
|
8376
|
+
return null;
|
|
8377
|
+
}
|
|
8035
8378
|
async function loadJsonObject(path, label) {
|
|
8036
8379
|
let payload;
|
|
8037
8380
|
try {
|
|
@@ -8255,11 +8598,18 @@ function readmeTemplate(template) {
|
|
|
8255
8598
|
"- `adapter.ts`: your AppAdapter implementation",
|
|
8256
8599
|
"- `manifest.json`: serialized AppManifest snapshot",
|
|
8257
8600
|
"- `tool_manual.json`: editable ToolManual draft for validation and registration",
|
|
8258
|
-
"- `runtime_validation.json`: live API smoke-test contract used during registration",
|
|
8601
|
+
"- `runtime_validation.json`: local live API smoke-test contract used during registration",
|
|
8602
|
+
"- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
|
|
8603
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
8259
8604
|
"",
|
|
8260
8605
|
"Before registering, replace all generated placeholders:",
|
|
8261
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
8262
|
-
"-
|
|
8606
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8607
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8608
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8609
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8610
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8611
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8612
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
8263
8613
|
"",
|
|
8264
8614
|
"Suggested workflow:",
|
|
8265
8615
|
"",
|
|
@@ -8270,11 +8620,14 @@ function readmeTemplate(template) {
|
|
|
8270
8620
|
"siglume score . --offline",
|
|
8271
8621
|
"```",
|
|
8272
8622
|
"",
|
|
8273
|
-
"After placeholders are replaced and `SIGLUME_API_KEY` is
|
|
8623
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8274
8624
|
"",
|
|
8275
8625
|
"```bash",
|
|
8276
8626
|
"siglume validate .",
|
|
8277
8627
|
"siglume score . --remote",
|
|
8628
|
+
"siglume preflight .",
|
|
8629
|
+
"siglume register .",
|
|
8630
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
8278
8631
|
"siglume register . --confirm",
|
|
8279
8632
|
"```",
|
|
8280
8633
|
""
|
|
@@ -8443,18 +8796,52 @@ async function runCli(argv, deps = {}) {
|
|
|
8443
8796
|
throw new SiglumeProjectError("Score failed.");
|
|
8444
8797
|
}
|
|
8445
8798
|
});
|
|
8446
|
-
program.command("
|
|
8799
|
+
program.command("preflight").option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8800
|
+
const report = await runPreflight(path, deps);
|
|
8801
|
+
if (options.json) {
|
|
8802
|
+
emit(stdout, renderJson(report));
|
|
8803
|
+
return;
|
|
8804
|
+
}
|
|
8805
|
+
emit(stdout, "Preflight passed.");
|
|
8806
|
+
const preflight = report.registration_preflight;
|
|
8807
|
+
if (preflight?.remote_quality) {
|
|
8808
|
+
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|
|
8809
|
+
}
|
|
8810
|
+
if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
|
|
8811
|
+
if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
|
|
8812
|
+
});
|
|
8813
|
+
program.command("register").option("--confirm", "confirm the draft registration immediately and publish it when the self-serve checks pass", false).option("--submit-review", "legacy alias: publish immediately if your environment still routes through submit-review", false).option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8447
8814
|
const report = await runRegistration(path, { confirm: options.confirm, submit_review: options.submitReview }, deps);
|
|
8448
8815
|
if (options.json) {
|
|
8449
8816
|
emit(stdout, renderJson(report));
|
|
8450
8817
|
} else {
|
|
8451
8818
|
const receipt = report.receipt;
|
|
8452
|
-
|
|
8819
|
+
if (report.confirmation) {
|
|
8820
|
+
emit(stdout, "Listing published.");
|
|
8821
|
+
} else if (report.review) {
|
|
8822
|
+
emit(stdout, "Listing published via legacy submit-review alias.");
|
|
8823
|
+
} else if (receipt.registration_mode === "upgrade") {
|
|
8824
|
+
emit(stdout, "Upgrade staged.");
|
|
8825
|
+
} else if (receipt.registration_mode === "refresh") {
|
|
8826
|
+
emit(stdout, "Draft refreshed.");
|
|
8827
|
+
} else {
|
|
8828
|
+
emit(stdout, "Draft listing created.");
|
|
8829
|
+
}
|
|
8453
8830
|
emit(stdout, `listing_id: ${receipt.listing_id}`);
|
|
8454
|
-
emit(stdout, `
|
|
8831
|
+
emit(stdout, `receipt_status: ${receipt.status}`);
|
|
8832
|
+
if (receipt.listing_status) emit(stdout, `listing_status: ${receipt.listing_status}`);
|
|
8833
|
+
if (receipt.oauth_status) emit(stdout, `oauth_configured: ${Boolean(receipt.oauth_status.configured)}`);
|
|
8455
8834
|
if (receipt.review_url) emit(stdout, `review_url: ${receipt.review_url}`);
|
|
8456
8835
|
if (receipt.trace_id) emit(stdout, `trace_id: ${receipt.trace_id}`);
|
|
8457
8836
|
if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);
|
|
8837
|
+
if (report.confirmation) {
|
|
8838
|
+
const confirmation = report.confirmation;
|
|
8839
|
+
if (confirmation.status) emit(stdout, `confirmation_status: ${confirmation.status}`);
|
|
8840
|
+
if (confirmation.release?.release_status) emit(stdout, `release_status: ${confirmation.release.release_status}`);
|
|
8841
|
+
} else if (report.review) {
|
|
8842
|
+
const review = report.review;
|
|
8843
|
+
if (review.status) emit(stdout, `publish_status: ${review.status}`);
|
|
8844
|
+
}
|
|
8458
8845
|
const preflight = report.registration_preflight;
|
|
8459
8846
|
if (preflight?.remote_quality) {
|
|
8460
8847
|
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|