@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.js
CHANGED
|
@@ -1330,6 +1330,9 @@ function parseListing(data) {
|
|
|
1330
1330
|
short_description: stringOrNull(data.short_description),
|
|
1331
1331
|
docs_url: stringOrNull(data.docs_url),
|
|
1332
1332
|
support_contact: stringOrNull(data.support_contact),
|
|
1333
|
+
seller_display_name: stringOrNull(data.seller_display_name),
|
|
1334
|
+
seller_homepage_url: stringOrNull(data.seller_homepage_url),
|
|
1335
|
+
seller_social_url: stringOrNull(data.seller_social_url),
|
|
1333
1336
|
review_status: stringOrNull(data.review_status),
|
|
1334
1337
|
review_note: stringOrNull(data.review_note),
|
|
1335
1338
|
submission_blockers: Array.isArray(data.submission_blockers) ? data.submission_blockers.filter((item) => typeof item === "string") : [],
|
|
@@ -2546,6 +2549,13 @@ var init_client = __esm({
|
|
|
2546
2549
|
if (options.runtime_validation) {
|
|
2547
2550
|
payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
|
|
2548
2551
|
}
|
|
2552
|
+
if (options.oauth_credentials) {
|
|
2553
|
+
payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
|
|
2554
|
+
items: options.oauth_credentials.map(
|
|
2555
|
+
(item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
|
|
2556
|
+
)
|
|
2557
|
+
} : coerceMapping(options.oauth_credentials, "oauth_credentials");
|
|
2558
|
+
}
|
|
2549
2559
|
if (options.metadata) {
|
|
2550
2560
|
payload.metadata = coerceMapping(options.metadata, "metadata");
|
|
2551
2561
|
}
|
|
@@ -2564,6 +2574,8 @@ var init_client = __esm({
|
|
|
2564
2574
|
"docs_url",
|
|
2565
2575
|
"documentation_url",
|
|
2566
2576
|
"support_contact",
|
|
2577
|
+
"seller_homepage_url",
|
|
2578
|
+
"seller_social_url",
|
|
2567
2579
|
"jurisdiction",
|
|
2568
2580
|
"price_model",
|
|
2569
2581
|
"price_value_minor",
|
|
@@ -2579,10 +2591,14 @@ var init_client = __esm({
|
|
|
2579
2591
|
}
|
|
2580
2592
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
2581
2593
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
2582
|
-
|
|
2594
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
2595
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
2596
|
+
if (docsUrl || supportContact || sellerHomepageUrl || sellerSocialUrl) {
|
|
2583
2597
|
const publisherIdentity = {
|
|
2584
2598
|
documentation_url: docsUrl || null,
|
|
2585
|
-
support_contact: supportContact || null
|
|
2599
|
+
support_contact: supportContact || null,
|
|
2600
|
+
seller_homepage_url: sellerHomepageUrl || null,
|
|
2601
|
+
seller_social_url: sellerSocialUrl || null
|
|
2586
2602
|
};
|
|
2587
2603
|
payload.publisher_identity = publisherIdentity;
|
|
2588
2604
|
payload.legal = { publisher_identity: publisherIdentity };
|
|
@@ -2596,36 +2612,39 @@ var init_client = __esm({
|
|
|
2596
2612
|
return {
|
|
2597
2613
|
listing_id,
|
|
2598
2614
|
status: String(data.status ?? "draft"),
|
|
2615
|
+
registration_mode: stringOrNull(data.registration_mode),
|
|
2616
|
+
listing_status: stringOrNull(data.listing_status),
|
|
2599
2617
|
auto_manifest: toRecord(data.auto_manifest),
|
|
2600
2618
|
confidence: toRecord(data.confidence),
|
|
2601
2619
|
validation_report: toRecord(data.validation_report),
|
|
2620
|
+
oauth_status: toRecord(data.oauth_status),
|
|
2602
2621
|
review_url: stringOrNull(data.review_url),
|
|
2603
2622
|
trace_id: meta.trace_id,
|
|
2604
2623
|
request_id: meta.request_id
|
|
2605
2624
|
};
|
|
2606
2625
|
}
|
|
2607
2626
|
async confirm_registration(listing_id, options = {}) {
|
|
2608
|
-
const
|
|
2609
|
-
const manifestPayload = options.manifest ? coerceMapping(options.manifest, "manifest") : pending?.manifest ?? {};
|
|
2610
|
-
const toolManualPayload = options.tool_manual ? coerceMapping(options.tool_manual, "tool_manual") : pending?.tool_manual ?? {};
|
|
2611
|
-
const overrides = {};
|
|
2612
|
-
for (const fieldName of ["name", "job_to_be_done"]) {
|
|
2613
|
-
if (manifestPayload[fieldName]) {
|
|
2614
|
-
overrides[fieldName] = manifestPayload[fieldName];
|
|
2615
|
-
}
|
|
2616
|
-
}
|
|
2617
|
-
if (Object.keys(toolManualPayload).length > 0) {
|
|
2618
|
-
overrides.tool_manual = toolManualPayload;
|
|
2619
|
-
}
|
|
2627
|
+
const { version_bump: versionBump } = options;
|
|
2620
2628
|
const payload = { approved: true };
|
|
2621
|
-
if (
|
|
2622
|
-
|
|
2629
|
+
if (versionBump !== void 0) {
|
|
2630
|
+
const allowed = ["patch", "minor", "major"];
|
|
2631
|
+
if (!allowed.includes(versionBump)) {
|
|
2632
|
+
throw new Error(
|
|
2633
|
+
`version_bump must be one of ${JSON.stringify(allowed)}, got ${JSON.stringify(versionBump)}`
|
|
2634
|
+
);
|
|
2635
|
+
}
|
|
2636
|
+
payload.version_bump = versionBump;
|
|
2623
2637
|
}
|
|
2624
2638
|
const [data, meta] = await this.request("POST", `/market/capabilities/${listing_id}/confirm-auto-register`, { json_body: payload });
|
|
2625
2639
|
this.pendingConfirmations.delete(listing_id);
|
|
2640
|
+
const checklist = isRecord(data.checklist) ? Object.fromEntries(
|
|
2641
|
+
Object.entries(data.checklist).map(([key, value]) => [key, Boolean(value)])
|
|
2642
|
+
) : {};
|
|
2626
2643
|
return {
|
|
2627
2644
|
listing_id: String(data.listing_id ?? listing_id),
|
|
2628
2645
|
status: String(data.status ?? ""),
|
|
2646
|
+
message: stringOrNull(data.message),
|
|
2647
|
+
checklist,
|
|
2629
2648
|
release: toRecord(data.release),
|
|
2630
2649
|
quality: parseRegistrationQuality(toRecord(data.quality)),
|
|
2631
2650
|
trace_id: meta.trace_id,
|
|
@@ -7145,6 +7164,15 @@ async function loadProject(path = ".") {
|
|
|
7145
7164
|
const tool_manual = tool_manual_path ? JSON.parse(await readFile(tool_manual_path, "utf8")) : buildToolManualTemplate(manifest);
|
|
7146
7165
|
const runtime_validation_path = await findRuntimeValidationPath(root_dir);
|
|
7147
7166
|
const runtime_validation = runtime_validation_path ? await loadJsonObject(runtime_validation_path, "runtime_validation") : void 0;
|
|
7167
|
+
const oauth_credentials_path = await findOauthCredentialsPath(root_dir);
|
|
7168
|
+
let oauth_credentials;
|
|
7169
|
+
if (oauth_credentials_path) {
|
|
7170
|
+
const parsed = JSON.parse(await readFile(oauth_credentials_path, "utf8"));
|
|
7171
|
+
if (!isRecord(parsed) && !Array.isArray(parsed)) {
|
|
7172
|
+
throw new SiglumeProjectError("oauth_credentials must be a JSON object or array");
|
|
7173
|
+
}
|
|
7174
|
+
oauth_credentials = parsed;
|
|
7175
|
+
}
|
|
7148
7176
|
return {
|
|
7149
7177
|
root_dir,
|
|
7150
7178
|
adapter_path,
|
|
@@ -7153,9 +7181,110 @@ async function loadProject(path = ".") {
|
|
|
7153
7181
|
tool_manual_path: tool_manual_path ?? void 0,
|
|
7154
7182
|
tool_manual,
|
|
7155
7183
|
runtime_validation_path: runtime_validation_path ?? void 0,
|
|
7156
|
-
runtime_validation
|
|
7184
|
+
runtime_validation,
|
|
7185
|
+
oauth_credentials_path: oauth_credentials_path ?? void 0,
|
|
7186
|
+
oauth_credentials
|
|
7157
7187
|
};
|
|
7158
7188
|
}
|
|
7189
|
+
var OAUTH_PROVIDER_ALIASES = {
|
|
7190
|
+
x: "twitter",
|
|
7191
|
+
"x-twitter": "twitter",
|
|
7192
|
+
twitter: "twitter",
|
|
7193
|
+
slack: "slack",
|
|
7194
|
+
google: "google",
|
|
7195
|
+
gmail: "google",
|
|
7196
|
+
"google-drive": "google",
|
|
7197
|
+
"google-calendar": "google",
|
|
7198
|
+
github: "github",
|
|
7199
|
+
linear: "linear",
|
|
7200
|
+
notion: "notion"
|
|
7201
|
+
};
|
|
7202
|
+
function oauthProviderKeyFromRequirement(value) {
|
|
7203
|
+
const raw = String(value ?? "").trim().toLowerCase().replaceAll("_", "-");
|
|
7204
|
+
if (!raw) return null;
|
|
7205
|
+
if (OAUTH_PROVIDER_ALIASES[raw]) {
|
|
7206
|
+
return OAUTH_PROVIDER_ALIASES[raw];
|
|
7207
|
+
}
|
|
7208
|
+
for (const token of raw.replaceAll("/", "-").replaceAll(":", "-").split("-")) {
|
|
7209
|
+
const next = token.trim();
|
|
7210
|
+
if (OAUTH_PROVIDER_ALIASES[next]) {
|
|
7211
|
+
return OAUTH_PROVIDER_ALIASES[next];
|
|
7212
|
+
}
|
|
7213
|
+
}
|
|
7214
|
+
return null;
|
|
7215
|
+
}
|
|
7216
|
+
function requiredOauthProviders(requirements) {
|
|
7217
|
+
const providers = [];
|
|
7218
|
+
for (const item of requirements ?? []) {
|
|
7219
|
+
const providerKey = oauthProviderKeyFromRequirement(item);
|
|
7220
|
+
if (providerKey && !providers.includes(providerKey)) {
|
|
7221
|
+
providers.push(providerKey);
|
|
7222
|
+
}
|
|
7223
|
+
}
|
|
7224
|
+
return providers;
|
|
7225
|
+
}
|
|
7226
|
+
function oauthProviderRecordsMap(payload) {
|
|
7227
|
+
if (!payload) {
|
|
7228
|
+
return {};
|
|
7229
|
+
}
|
|
7230
|
+
const items = Array.isArray(payload) ? payload : Array.isArray(payload.items) ? payload.items : [payload];
|
|
7231
|
+
const resolved = {};
|
|
7232
|
+
for (const [index, item] of items.entries()) {
|
|
7233
|
+
if (!isRecord(item)) {
|
|
7234
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must be a JSON object.`);
|
|
7235
|
+
}
|
|
7236
|
+
const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
|
|
7237
|
+
if (!providerKey) {
|
|
7238
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is unsupported.`);
|
|
7239
|
+
}
|
|
7240
|
+
const clientId = String(item.client_id ?? "").trim();
|
|
7241
|
+
const clientSecret = String(item.client_secret ?? "").trim();
|
|
7242
|
+
if (!clientId || !clientSecret) {
|
|
7243
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must include client_id and client_secret.`);
|
|
7244
|
+
}
|
|
7245
|
+
const rawScopes = item.required_scopes ?? item.scopes;
|
|
7246
|
+
let scopes = [];
|
|
7247
|
+
if (rawScopes == null) {
|
|
7248
|
+
scopes = [];
|
|
7249
|
+
} else if (!Array.isArray(rawScopes)) {
|
|
7250
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].required_scopes must be a JSON array.`);
|
|
7251
|
+
} else {
|
|
7252
|
+
scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
|
|
7253
|
+
}
|
|
7254
|
+
resolved[providerKey] = {
|
|
7255
|
+
provider_key: providerKey,
|
|
7256
|
+
client_id: clientId,
|
|
7257
|
+
client_secret: clientSecret,
|
|
7258
|
+
required_scopes: scopes
|
|
7259
|
+
};
|
|
7260
|
+
}
|
|
7261
|
+
return resolved;
|
|
7262
|
+
}
|
|
7263
|
+
function canonicalOauthCredentialsPayload(payload) {
|
|
7264
|
+
const records = oauthProviderRecordsMap(payload);
|
|
7265
|
+
const providerKeys = Object.keys(records).sort();
|
|
7266
|
+
if (providerKeys.length === 0) {
|
|
7267
|
+
return void 0;
|
|
7268
|
+
}
|
|
7269
|
+
return {
|
|
7270
|
+
items: providerKeys.map((providerKey) => records[providerKey])
|
|
7271
|
+
};
|
|
7272
|
+
}
|
|
7273
|
+
function ensureRequiredOauthCredentials(project) {
|
|
7274
|
+
const requiredProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7275
|
+
if (requiredProviders.length === 0) {
|
|
7276
|
+
return;
|
|
7277
|
+
}
|
|
7278
|
+
const provided = new Set(Object.keys(oauthProviderRecordsMap(project.oauth_credentials)));
|
|
7279
|
+
const missing = requiredProviders.filter((provider) => !provided.has(provider));
|
|
7280
|
+
if (missing.length === 0) {
|
|
7281
|
+
return;
|
|
7282
|
+
}
|
|
7283
|
+
const path = project.oauth_credentials_path ?? join(project.root_dir, "oauth_credentials.json");
|
|
7284
|
+
throw new SiglumeProjectError(
|
|
7285
|
+
`${path} is required for OAuth-backed APIs. Missing provider seeds: ${missing.join(", ")}`
|
|
7286
|
+
);
|
|
7287
|
+
}
|
|
7159
7288
|
async function validateProject(path = ".", deps = {}) {
|
|
7160
7289
|
const project = await loadProject(path);
|
|
7161
7290
|
const manifest_issues = await projectValidationIssues(project);
|
|
@@ -7192,17 +7321,31 @@ function ensureManifestPublisherIdentity(project) {
|
|
|
7192
7321
|
const manifestPayload = project.manifest;
|
|
7193
7322
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
7194
7323
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
7324
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
7325
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
7195
7326
|
const jurisdiction = String(manifestPayload.jurisdiction ?? "").trim();
|
|
7196
7327
|
const issues = [];
|
|
7197
7328
|
if (!docsUrl) {
|
|
7198
7329
|
issues.push("manifest.docs_url is required");
|
|
7199
7330
|
} else if (looksLikePlaceholder(docsUrl)) {
|
|
7200
7331
|
issues.push("manifest.docs_url must be replaced with your public documentation URL");
|
|
7332
|
+
} else if (!looksLikeHttpUrl(docsUrl)) {
|
|
7333
|
+
issues.push("manifest.docs_url must be an http(s) URL");
|
|
7334
|
+
} else if (looksLikeRootUrl(docsUrl)) {
|
|
7335
|
+
issues.push("manifest.docs_url must be a dedicated API usage page, not a root homepage URL");
|
|
7201
7336
|
}
|
|
7202
7337
|
if (!supportContact) {
|
|
7203
7338
|
issues.push("manifest.support_contact is required");
|
|
7204
7339
|
} else if (looksLikePlaceholder(supportContact)) {
|
|
7205
7340
|
issues.push("manifest.support_contact must be replaced with your real support email or support URL");
|
|
7341
|
+
} else if (!looksLikeEmail(supportContact) && !looksLikeHttpUrl(supportContact)) {
|
|
7342
|
+
issues.push("manifest.support_contact must be a real email address or http(s) support URL");
|
|
7343
|
+
}
|
|
7344
|
+
if (sellerHomepageUrl && (looksLikePlaceholder(sellerHomepageUrl) || !looksLikeHttpUrl(sellerHomepageUrl))) {
|
|
7345
|
+
issues.push("manifest.seller_homepage_url must be a real http(s) official homepage URL when provided");
|
|
7346
|
+
}
|
|
7347
|
+
if (sellerSocialUrl && (looksLikePlaceholder(sellerSocialUrl) || !looksLikeHttpUrl(sellerSocialUrl))) {
|
|
7348
|
+
issues.push("manifest.seller_social_url must be a real http(s) official social/profile URL when provided");
|
|
7206
7349
|
}
|
|
7207
7350
|
if (!jurisdiction) issues.push("manifest.jurisdiction is required");
|
|
7208
7351
|
if (issues.length > 0) {
|
|
@@ -7214,7 +7357,25 @@ ${issues.map((issue2) => `- ${issue2}`).join("\n")}`
|
|
|
7214
7357
|
}
|
|
7215
7358
|
function looksLikePlaceholder(value) {
|
|
7216
7359
|
const normalized = value.trim().toLowerCase();
|
|
7217
|
-
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");
|
|
7360
|
+
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");
|
|
7361
|
+
}
|
|
7362
|
+
function looksLikeHttpUrl(value) {
|
|
7363
|
+
try {
|
|
7364
|
+
const parsed = new URL(value.trim());
|
|
7365
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
7366
|
+
} catch {
|
|
7367
|
+
return false;
|
|
7368
|
+
}
|
|
7369
|
+
}
|
|
7370
|
+
function looksLikeRootUrl(value) {
|
|
7371
|
+
if (!looksLikeHttpUrl(value)) return false;
|
|
7372
|
+
const parsed = new URL(value.trim());
|
|
7373
|
+
return parsed.pathname.replace(/^\/+|\/+$/g, "") === "";
|
|
7374
|
+
}
|
|
7375
|
+
function looksLikeEmail(value) {
|
|
7376
|
+
const normalized = value.trim();
|
|
7377
|
+
const domain = normalized.split("@").at(-1) ?? "";
|
|
7378
|
+
return normalized.includes("@") && !normalized.includes(" ") && domain.includes(".") && !normalized.startsWith("@");
|
|
7218
7379
|
}
|
|
7219
7380
|
function runtimePlaceholderIssues(runtimeValidation) {
|
|
7220
7381
|
const issues = [];
|
|
@@ -7274,6 +7435,9 @@ async function registrationPreflight(project, client) {
|
|
|
7274
7435
|
const manifestIssues = await projectValidationIssues(project);
|
|
7275
7436
|
const [toolManualValid, toolManualIssues] = validate_tool_manual(project.tool_manual);
|
|
7276
7437
|
const remoteQuality = await client.preview_quality_score(project.tool_manual);
|
|
7438
|
+
const requiredOauthProvidersList = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7439
|
+
const oauthProviderRecords = oauthProviderRecordsMap(project.oauth_credentials);
|
|
7440
|
+
const missingOauthProviders = requiredOauthProvidersList.filter((provider) => !oauthProviderRecords[provider]);
|
|
7277
7441
|
const blockingToolManualIssues = toolManualIssues.filter((issue2) => issue2.severity === "error");
|
|
7278
7442
|
const errors = [
|
|
7279
7443
|
...manifestIssues.map((issue2) => String(issue2)),
|
|
@@ -7285,11 +7449,17 @@ async function registrationPreflight(project, client) {
|
|
|
7285
7449
|
if (!remoteQualityOk(remoteQuality)) {
|
|
7286
7450
|
errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
|
|
7287
7451
|
}
|
|
7452
|
+
if (missingOauthProviders.length > 0) {
|
|
7453
|
+
errors.push(`oauth_credentials.json is required for OAuth-backed APIs: ${missingOauthProviders.join(", ")}`);
|
|
7454
|
+
}
|
|
7288
7455
|
const preflight = {
|
|
7289
7456
|
manifest_issues: manifestIssues,
|
|
7290
7457
|
tool_manual_valid: toolManualValid,
|
|
7291
7458
|
tool_manual_issues: toolManualIssues.map((issue2) => toJsonable(issue2)),
|
|
7292
7459
|
remote_quality: toJsonable(remoteQuality),
|
|
7460
|
+
required_oauth_providers: requiredOauthProvidersList,
|
|
7461
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null,
|
|
7462
|
+
oauth_missing_providers: missingOauthProviders,
|
|
7293
7463
|
ok: errors.length === 0
|
|
7294
7464
|
};
|
|
7295
7465
|
if (errors.length > 0) {
|
|
@@ -7305,6 +7475,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7305
7475
|
ensureExplicitToolManual(project);
|
|
7306
7476
|
ensureManifestPublisherIdentity(project);
|
|
7307
7477
|
ensureRuntimeValidationReady(project);
|
|
7478
|
+
ensureRequiredOauthCredentials(project);
|
|
7308
7479
|
const client = await createClient(deps);
|
|
7309
7480
|
const preflight = await registrationPreflight(project, client);
|
|
7310
7481
|
let developerPortalPreflight = null;
|
|
@@ -7313,18 +7484,20 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7313
7484
|
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7314
7485
|
if (verifiedDestination !== true) {
|
|
7315
7486
|
throw new SiglumeProjectError(
|
|
7316
|
-
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/
|
|
7487
|
+
"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."
|
|
7317
7488
|
);
|
|
7318
7489
|
}
|
|
7319
7490
|
developerPortalPreflight = toJsonable(portal);
|
|
7320
7491
|
}
|
|
7321
7492
|
const receipt = await client.auto_register(project.manifest, project.tool_manual, {
|
|
7322
|
-
runtime_validation: project.runtime_validation
|
|
7493
|
+
runtime_validation: project.runtime_validation,
|
|
7494
|
+
oauth_credentials: canonicalOauthCredentialsPayload(project.oauth_credentials)
|
|
7323
7495
|
});
|
|
7324
7496
|
const result = {
|
|
7325
7497
|
receipt: toJsonable(receipt),
|
|
7326
7498
|
registration_preflight: preflight,
|
|
7327
|
-
runtime_validation_path: project.runtime_validation_path ?? null
|
|
7499
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7500
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7328
7501
|
};
|
|
7329
7502
|
if (developerPortalPreflight) {
|
|
7330
7503
|
result.developer_portal_preflight = developerPortalPreflight;
|
|
@@ -7339,6 +7512,37 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7339
7512
|
}
|
|
7340
7513
|
return result;
|
|
7341
7514
|
}
|
|
7515
|
+
async function runPreflight(path = ".", deps = {}) {
|
|
7516
|
+
const project = await loadProject(path);
|
|
7517
|
+
ensureExplicitToolManual(project);
|
|
7518
|
+
ensureManifestPublisherIdentity(project);
|
|
7519
|
+
ensureRuntimeValidationReady(project);
|
|
7520
|
+
ensureRequiredOauthCredentials(project);
|
|
7521
|
+
const client = await createClient(deps);
|
|
7522
|
+
const preflight = await registrationPreflight(project, client);
|
|
7523
|
+
let developerPortalPreflight = null;
|
|
7524
|
+
if (String(project.manifest.price_model ?? "free").toLowerCase() !== "free") {
|
|
7525
|
+
const portal = await client.get_developer_portal();
|
|
7526
|
+
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7527
|
+
if (verifiedDestination !== true) {
|
|
7528
|
+
throw new SiglumeProjectError(
|
|
7529
|
+
"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."
|
|
7530
|
+
);
|
|
7531
|
+
}
|
|
7532
|
+
developerPortalPreflight = toJsonable(portal);
|
|
7533
|
+
}
|
|
7534
|
+
const result = {
|
|
7535
|
+
ok: true,
|
|
7536
|
+
adapter_path: project.adapter_path,
|
|
7537
|
+
registration_preflight: preflight,
|
|
7538
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7539
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7540
|
+
};
|
|
7541
|
+
if (developerPortalPreflight) {
|
|
7542
|
+
result.developer_portal_preflight = developerPortalPreflight;
|
|
7543
|
+
}
|
|
7544
|
+
return result;
|
|
7545
|
+
}
|
|
7342
7546
|
async function createSupportCaseReport(options, deps = {}) {
|
|
7343
7547
|
const client = await createClient(deps);
|
|
7344
7548
|
const supportCase = await client.create_support_case(options.subject, options.body, { trace_id: options.trace_id });
|
|
@@ -7385,8 +7589,12 @@ async function writeInitTemplate(template, destination) {
|
|
|
7385
7589
|
const manifest_path = join(root, "manifest.json");
|
|
7386
7590
|
const tool_manual_path = join(root, "tool_manual.json");
|
|
7387
7591
|
const runtime_validation_path = join(root, "runtime_validation.json");
|
|
7592
|
+
const gitignore_path = join(root, ".gitignore");
|
|
7388
7593
|
const readme_path = join(root, "README.md");
|
|
7389
|
-
|
|
7594
|
+
const docs_dir = join(root, "docs");
|
|
7595
|
+
await mkdir(docs_dir, { recursive: true });
|
|
7596
|
+
const docs_usage_path = join(docs_dir, "api-usage.md");
|
|
7597
|
+
for (const filePath of [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, readme_path]) {
|
|
7390
7598
|
if (existsSync(filePath)) {
|
|
7391
7599
|
throw new SiglumeProjectError(`${basename(filePath)} already exists in ${root}`);
|
|
7392
7600
|
}
|
|
@@ -7397,8 +7605,10 @@ async function writeInitTemplate(template, destination) {
|
|
|
7397
7605
|
await writeFile(manifest_path, renderJson(manifest), "utf8");
|
|
7398
7606
|
await writeFile(tool_manual_path, renderJson(toolManual), "utf8");
|
|
7399
7607
|
await writeFile(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(toolManual)), "utf8");
|
|
7608
|
+
await writeFile(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
7609
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7400
7610
|
await writeFile(readme_path, readmeTemplate(template), "utf8");
|
|
7401
|
-
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, readme_path];
|
|
7611
|
+
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, gitignore_path, readme_path];
|
|
7402
7612
|
}
|
|
7403
7613
|
async function listOperationCatalog(options = {}, deps = {}) {
|
|
7404
7614
|
const resolvedAgentId = String(options.agent_id ?? "").trim();
|
|
@@ -7792,12 +8002,19 @@ function operationReadmeTemplate(operation, manifest, warning) {
|
|
|
7792
8002
|
"- `stubs.ts`: mock fallback used when `SIGLUME_API_KEY` is not set",
|
|
7793
8003
|
"- `manifest.json`: reviewable manifest snapshot",
|
|
7794
8004
|
"- `tool_manual.json`: machine-generated ToolManual scaffold",
|
|
7795
|
-
"- `runtime_validation.json`: public endpoint and review-key checks used by auto-register",
|
|
8005
|
+
"- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
|
|
8006
|
+
"- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
|
|
8007
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
7796
8008
|
"- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
|
|
7797
8009
|
"",
|
|
7798
8010
|
"Before registering, replace all generated placeholders:",
|
|
7799
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
7800
|
-
"-
|
|
8011
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8012
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8013
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8014
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8015
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8016
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8017
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
7801
8018
|
"",
|
|
7802
8019
|
"## Commands",
|
|
7803
8020
|
"",
|
|
@@ -7809,16 +8026,108 @@ function operationReadmeTemplate(operation, manifest, warning) {
|
|
|
7809
8026
|
"siglume score . --offline",
|
|
7810
8027
|
"```",
|
|
7811
8028
|
"",
|
|
7812
|
-
"After placeholders are replaced and `SIGLUME_API_KEY` is
|
|
8029
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
7813
8030
|
"",
|
|
7814
8031
|
"```bash",
|
|
7815
8032
|
"siglume validate .",
|
|
7816
8033
|
"siglume score . --remote",
|
|
8034
|
+
"siglume preflight .",
|
|
8035
|
+
"siglume register .",
|
|
8036
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
7817
8037
|
"siglume register . --confirm",
|
|
7818
8038
|
"```",
|
|
7819
8039
|
""
|
|
7820
8040
|
].join("\n");
|
|
7821
8041
|
}
|
|
8042
|
+
function apiUsageDocsTemplate(manifest) {
|
|
8043
|
+
const name = String(manifest.name ?? manifest.capability_key ?? "Siglume API");
|
|
8044
|
+
const capabilityKey = String(manifest.capability_key ?? "replace-with-capability-key");
|
|
8045
|
+
const jobToBeDone = String(manifest.job_to_be_done ?? "Describe what this API lets an agent do.");
|
|
8046
|
+
const permissionClass = String(manifest.permission_class ?? "read-only");
|
|
8047
|
+
const priceModel = String(manifest.price_model ?? "free");
|
|
8048
|
+
const requiredAccounts = (manifest.required_connected_accounts ?? []).join(", ") || "none";
|
|
8049
|
+
const supportContact = String(manifest.support_contact ?? "replace-with-support-contact");
|
|
8050
|
+
return [
|
|
8051
|
+
`# ${name} API Usage Guide`,
|
|
8052
|
+
"",
|
|
8053
|
+
`This page is the dedicated public usage guide for the Siglume API listing \`${capabilityKey}\`.`,
|
|
8054
|
+
"Publish this page at an anonymous HTTP 200 URL and use that URL as `docs_url`.",
|
|
8055
|
+
"",
|
|
8056
|
+
"Do not use your company homepage as `docs_url`; keep seller/company homepages in `seller_homepage_url`.",
|
|
8057
|
+
"",
|
|
8058
|
+
"## What This API Does",
|
|
8059
|
+
"",
|
|
8060
|
+
jobToBeDone,
|
|
8061
|
+
"",
|
|
8062
|
+
"## Permission Model",
|
|
8063
|
+
"",
|
|
8064
|
+
`- Permission class: \`${permissionClass}\``,
|
|
8065
|
+
`- Price model: \`${priceModel}\``,
|
|
8066
|
+
`- Required connected accounts: \`${requiredAccounts}\``,
|
|
8067
|
+
"",
|
|
8068
|
+
"## Inputs",
|
|
8069
|
+
"",
|
|
8070
|
+
"Describe the request fields your API accepts. Keep this aligned with `tool_manual.json` and `runtime_validation.json`.",
|
|
8071
|
+
"",
|
|
8072
|
+
"## Outputs",
|
|
8073
|
+
"",
|
|
8074
|
+
"Describe the response fields your API returns. Include the fields in `runtime_validation.expected_response_fields`.",
|
|
8075
|
+
"",
|
|
8076
|
+
"## Errors And Support",
|
|
8077
|
+
"",
|
|
8078
|
+
"Explain common error messages and how an owner should recover.",
|
|
8079
|
+
"",
|
|
8080
|
+
`Support contact: ${supportContact}`,
|
|
8081
|
+
""
|
|
8082
|
+
].join("\n");
|
|
8083
|
+
}
|
|
8084
|
+
function generatedGitignore() {
|
|
8085
|
+
return [
|
|
8086
|
+
"# Local secrets and registration-only runtime checks.",
|
|
8087
|
+
".env",
|
|
8088
|
+
".env.*",
|
|
8089
|
+
"!.env.example",
|
|
8090
|
+
"runtime_validation.json",
|
|
8091
|
+
"runtime-validation.json",
|
|
8092
|
+
"oauth_credentials.json",
|
|
8093
|
+
"oauth-credentials.json",
|
|
8094
|
+
"",
|
|
8095
|
+
"# Python / test artifacts.",
|
|
8096
|
+
"__pycache__/",
|
|
8097
|
+
"*.py[cod]",
|
|
8098
|
+
".pytest_cache/",
|
|
8099
|
+
".mypy_cache/",
|
|
8100
|
+
".coverage",
|
|
8101
|
+
"htmlcov/",
|
|
8102
|
+
"dist/",
|
|
8103
|
+
"build/",
|
|
8104
|
+
"*.egg-info/",
|
|
8105
|
+
"",
|
|
8106
|
+
"# JavaScript tooling if this project also uses TypeScript helpers.",
|
|
8107
|
+
"node_modules/",
|
|
8108
|
+
"coverage/",
|
|
8109
|
+
""
|
|
8110
|
+
].join("\n");
|
|
8111
|
+
}
|
|
8112
|
+
async function writeOrMergeGitignore(filePath) {
|
|
8113
|
+
const generated = generatedGitignore();
|
|
8114
|
+
if (!existsSync(filePath)) {
|
|
8115
|
+
await writeFile(filePath, generated, "utf8");
|
|
8116
|
+
return;
|
|
8117
|
+
}
|
|
8118
|
+
const existing = await readFile(filePath, "utf8");
|
|
8119
|
+
const existingEntries = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
|
|
8120
|
+
const additions = generated.split(/\r?\n/).filter((line) => line.trim() && !existingEntries.has(line.trim()));
|
|
8121
|
+
if (additions.length === 0) {
|
|
8122
|
+
return;
|
|
8123
|
+
}
|
|
8124
|
+
const prefix = existing.endsWith("\n") ? existing : `${existing}
|
|
8125
|
+
`;
|
|
8126
|
+
await writeFile(filePath, `${prefix}
|
|
8127
|
+
# Siglume generated ignores.
|
|
8128
|
+
${additions.join("\n")}
|
|
8129
|
+
`, "utf8");
|
|
8130
|
+
}
|
|
7822
8131
|
async function writeOperationTemplate(operation_key, destination, options = {}, deps = {}) {
|
|
7823
8132
|
const root = resolve(destination);
|
|
7824
8133
|
await mkdir(root, { recursive: true });
|
|
@@ -7829,9 +8138,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7829
8138
|
const manifest_path = join(root, "manifest.json");
|
|
7830
8139
|
const tool_manual_path = join(root, "tool_manual.json");
|
|
7831
8140
|
const runtime_validation_path = join(root, "runtime_validation.json");
|
|
8141
|
+
const gitignore_path = join(root, ".gitignore");
|
|
7832
8142
|
const readme_path = join(root, "README.md");
|
|
7833
8143
|
const test_path = join(testsDir, "test_adapter.ts");
|
|
7834
|
-
|
|
8144
|
+
const docs_dir = join(root, "docs");
|
|
8145
|
+
await mkdir(docs_dir, { recursive: true });
|
|
8146
|
+
const docs_usage_path = join(docs_dir, "api-usage.md");
|
|
8147
|
+
for (const filePath of [
|
|
8148
|
+
adapter_path,
|
|
8149
|
+
stubs_path,
|
|
8150
|
+
manifest_path,
|
|
8151
|
+
tool_manual_path,
|
|
8152
|
+
runtime_validation_path,
|
|
8153
|
+
docs_usage_path,
|
|
8154
|
+
readme_path,
|
|
8155
|
+
test_path
|
|
8156
|
+
]) {
|
|
7835
8157
|
if (existsSync(filePath)) {
|
|
7836
8158
|
throw new SiglumeProjectError(`${basename(filePath)} already exists in ${root}`);
|
|
7837
8159
|
}
|
|
@@ -7859,10 +8181,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7859
8181
|
await writeFile(manifest_path, renderJson(manifest), "utf8");
|
|
7860
8182
|
await writeFile(tool_manual_path, renderJson(tool_manual), "utf8");
|
|
7861
8183
|
await writeFile(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(tool_manual)), "utf8");
|
|
8184
|
+
await writeFile(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
8185
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7862
8186
|
await writeFile(readme_path, operationReadmeTemplate(operation, manifest, warning), "utf8");
|
|
7863
8187
|
await writeFile(test_path, operationTestSource(operation), "utf8");
|
|
7864
8188
|
return {
|
|
7865
|
-
files: [
|
|
8189
|
+
files: [
|
|
8190
|
+
adapter_path,
|
|
8191
|
+
stubs_path,
|
|
8192
|
+
manifest_path,
|
|
8193
|
+
tool_manual_path,
|
|
8194
|
+
runtime_validation_path,
|
|
8195
|
+
docs_usage_path,
|
|
8196
|
+
gitignore_path,
|
|
8197
|
+
readme_path,
|
|
8198
|
+
test_path
|
|
8199
|
+
],
|
|
7866
8200
|
operation,
|
|
7867
8201
|
report: {
|
|
7868
8202
|
tool_manual_valid,
|
|
@@ -8011,6 +8345,15 @@ async function findRuntimeValidationPath(root_dir) {
|
|
|
8011
8345
|
}
|
|
8012
8346
|
return null;
|
|
8013
8347
|
}
|
|
8348
|
+
async function findOauthCredentialsPath(root_dir) {
|
|
8349
|
+
for (const name of ["oauth_credentials.json", "oauth-credentials.json"]) {
|
|
8350
|
+
const candidate = join(root_dir, name);
|
|
8351
|
+
if (existsSync(candidate)) {
|
|
8352
|
+
return candidate;
|
|
8353
|
+
}
|
|
8354
|
+
}
|
|
8355
|
+
return null;
|
|
8356
|
+
}
|
|
8014
8357
|
async function loadJsonObject(path, label) {
|
|
8015
8358
|
let payload;
|
|
8016
8359
|
try {
|
|
@@ -8234,11 +8577,18 @@ function readmeTemplate(template) {
|
|
|
8234
8577
|
"- `adapter.ts`: your AppAdapter implementation",
|
|
8235
8578
|
"- `manifest.json`: serialized AppManifest snapshot",
|
|
8236
8579
|
"- `tool_manual.json`: editable ToolManual draft for validation and registration",
|
|
8237
|
-
"- `runtime_validation.json`: live API smoke-test contract used during registration",
|
|
8580
|
+
"- `runtime_validation.json`: local live API smoke-test contract used during registration",
|
|
8581
|
+
"- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
|
|
8582
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
8238
8583
|
"",
|
|
8239
8584
|
"Before registering, replace all generated placeholders:",
|
|
8240
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
8241
|
-
"-
|
|
8585
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8586
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8587
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8588
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8589
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8590
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8591
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
8242
8592
|
"",
|
|
8243
8593
|
"Suggested workflow:",
|
|
8244
8594
|
"",
|
|
@@ -8249,11 +8599,14 @@ function readmeTemplate(template) {
|
|
|
8249
8599
|
"siglume score . --offline",
|
|
8250
8600
|
"```",
|
|
8251
8601
|
"",
|
|
8252
|
-
"After placeholders are replaced and `SIGLUME_API_KEY` is
|
|
8602
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8253
8603
|
"",
|
|
8254
8604
|
"```bash",
|
|
8255
8605
|
"siglume validate .",
|
|
8256
8606
|
"siglume score . --remote",
|
|
8607
|
+
"siglume preflight .",
|
|
8608
|
+
"siglume register .",
|
|
8609
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
8257
8610
|
"siglume register . --confirm",
|
|
8258
8611
|
"```",
|
|
8259
8612
|
""
|
|
@@ -8422,18 +8775,52 @@ async function runCli(argv, deps = {}) {
|
|
|
8422
8775
|
throw new SiglumeProjectError("Score failed.");
|
|
8423
8776
|
}
|
|
8424
8777
|
});
|
|
8425
|
-
program.command("
|
|
8778
|
+
program.command("preflight").option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8779
|
+
const report = await runPreflight(path, deps);
|
|
8780
|
+
if (options.json) {
|
|
8781
|
+
emit(stdout, renderJson(report));
|
|
8782
|
+
return;
|
|
8783
|
+
}
|
|
8784
|
+
emit(stdout, "Preflight passed.");
|
|
8785
|
+
const preflight = report.registration_preflight;
|
|
8786
|
+
if (preflight?.remote_quality) {
|
|
8787
|
+
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|
|
8788
|
+
}
|
|
8789
|
+
if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
|
|
8790
|
+
if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
|
|
8791
|
+
});
|
|
8792
|
+
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) => {
|
|
8426
8793
|
const report = await runRegistration(path, { confirm: options.confirm, submit_review: options.submitReview }, deps);
|
|
8427
8794
|
if (options.json) {
|
|
8428
8795
|
emit(stdout, renderJson(report));
|
|
8429
8796
|
} else {
|
|
8430
8797
|
const receipt = report.receipt;
|
|
8431
|
-
|
|
8798
|
+
if (report.confirmation) {
|
|
8799
|
+
emit(stdout, "Listing published.");
|
|
8800
|
+
} else if (report.review) {
|
|
8801
|
+
emit(stdout, "Listing published via legacy submit-review alias.");
|
|
8802
|
+
} else if (receipt.registration_mode === "upgrade") {
|
|
8803
|
+
emit(stdout, "Upgrade staged.");
|
|
8804
|
+
} else if (receipt.registration_mode === "refresh") {
|
|
8805
|
+
emit(stdout, "Draft refreshed.");
|
|
8806
|
+
} else {
|
|
8807
|
+
emit(stdout, "Draft listing created.");
|
|
8808
|
+
}
|
|
8432
8809
|
emit(stdout, `listing_id: ${receipt.listing_id}`);
|
|
8433
|
-
emit(stdout, `
|
|
8810
|
+
emit(stdout, `receipt_status: ${receipt.status}`);
|
|
8811
|
+
if (receipt.listing_status) emit(stdout, `listing_status: ${receipt.listing_status}`);
|
|
8812
|
+
if (receipt.oauth_status) emit(stdout, `oauth_configured: ${Boolean(receipt.oauth_status.configured)}`);
|
|
8434
8813
|
if (receipt.review_url) emit(stdout, `review_url: ${receipt.review_url}`);
|
|
8435
8814
|
if (receipt.trace_id) emit(stdout, `trace_id: ${receipt.trace_id}`);
|
|
8436
8815
|
if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);
|
|
8816
|
+
if (report.confirmation) {
|
|
8817
|
+
const confirmation = report.confirmation;
|
|
8818
|
+
if (confirmation.status) emit(stdout, `confirmation_status: ${confirmation.status}`);
|
|
8819
|
+
if (confirmation.release?.release_status) emit(stdout, `release_status: ${confirmation.release.release_status}`);
|
|
8820
|
+
} else if (report.review) {
|
|
8821
|
+
const review = report.review;
|
|
8822
|
+
if (review.status) emit(stdout, `publish_status: ${review.status}`);
|
|
8823
|
+
}
|
|
8437
8824
|
const preflight = report.registration_preflight;
|
|
8438
8825
|
if (preflight?.remote_quality) {
|
|
8439
8826
|
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|