@siglume/api-sdk 1.2.2 → 2.0.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 CHANGED
@@ -27,7 +27,7 @@ Buyer-side discovery and export helpers are also included:
27
27
  import { SiglumeBuyerClient, to_anthropic_tool } from "@siglume/api-sdk";
28
28
 
29
29
  const buyer = new SiglumeBuyerClient({
30
- api_key: process.env.SIGLUME_API_KEY ?? "sig_mock_key",
30
+ api_key: process.env.SIGLUME_OWNER_SESSION_BEARER!,
31
31
  default_agent_id: process.env.SIGLUME_AGENT_ID,
32
32
  });
33
33
 
@@ -73,7 +73,7 @@ siglume register . --company company_123
73
73
 
74
74
  `siglume register` reads `tool_manual.json`, the local Git-ignored
75
75
  `runtime_validation.json`. Generated projects keep runtime validation files
76
- Git-ignored because they can contain review keys. SDK / HTTP automation can pass
76
+ Git-ignored because they hold the runtime auth header shared secret. SDK / HTTP automation can pass
77
77
  `source_url`, `source_context`, and `input_form_spec` directly to
78
78
  `auto-register`. The CLI runs preflight by default, then calls the same
79
79
  `auto-register` route used by SDK / automation clients and confirms publication
@@ -88,6 +88,14 @@ public-order / morals compliance.
88
88
  For the canonical pricing reference, see
89
89
  [`../docs/pricing-and-billing.md`](../docs/pricing-and-billing.md).
90
90
 
91
+ Developer-funded reward or incentive payouts are not normal SDK/API-key calls.
92
+ Do not call MCP Gateway with `SIGLUME_API_KEY`, `cli_...`, `X-API-Key`, or
93
+ `X-Siglume-API-Key`. Reward payout execution uses
94
+ `https://mcp.siglume.com/` with `Authorization: Bearer mcpsk_...` and
95
+ `tools/call market_create_reward_payout`; SDK/API keys remain for
96
+ registration, validation, and listing automation. See
97
+ [`../docs/web3-settlement.md#generic-reward-payouts`](../docs/web3-settlement.md#generic-reward-payouts).
98
+
91
99
  Use `price_model: PriceModel.USAGE_BASED` or `PriceModel.PER_ACTION` when the
92
100
  API must execute before the final operation is known. These listings are free to
93
101
  invoke up front. Your adapter returns the executed operation in
@@ -145,6 +153,15 @@ then calls the ACTION endpoint with the same token as `commit_token`. If payment
145
153
  fails, the ACTION call is never made. Use the default `"post"` timing only for
146
154
  read-only or reversible usage.
147
155
 
156
+ Responsibility boundary: Siglume owns payment, authorization, platform
157
+ idempotency, retry state, usage rows, and reconciliation state. Your API owns
158
+ the provider-specific action and the proof that it committed. The platform does
159
+ not infer whether an X post, email, CRM write, booking, or other external action
160
+ happened. Return committed evidence only after the side effect committed;
161
+ draft-only, preview, ambiguous, or `status="ready"` live-action results are not
162
+ delivered results. See
163
+ [`../docs/platform-api-boundary.md`](../docs/platform-api-boundary.md).
164
+
148
165
  After live or sandbox execution, inspect receipts with `siglume dev tail`,
149
166
  `siglume dev tail --listing-id <listing_id>`, or the SDK receipt helpers. The
150
167
  publisher listing view is privacy-redacted. See
@@ -354,7 +354,12 @@ var init_webhooks = __esm({
354
354
  "capability.published",
355
355
  "capability.delisted",
356
356
  "execution.completed",
357
- "execution.failed"
357
+ "execution.failed",
358
+ "reward_payout.created",
359
+ "reward_payout.provider_pending",
360
+ "reward_paid",
361
+ "reward_payout.failed",
362
+ "reward_payout.cancelled"
358
363
  ];
359
364
  WEBHOOK_EVENT_SET = new Set(WEBHOOK_EVENT_TYPES);
360
365
  }
@@ -1404,6 +1409,23 @@ function validatePricingPlanFloor(plan, defaultCurrency) {
1404
1409
  function pricingPlanHasItems(plan) {
1405
1410
  return isRecord(plan) && Array.isArray(plan.items) && plan.items.length > 0;
1406
1411
  }
1412
+ function validateListingTextLengths(payload) {
1413
+ const limits = {
1414
+ short_description: LISTING_SHORT_DESCRIPTION_MAX_LENGTH,
1415
+ job_to_be_done: LISTING_JOB_TO_BE_DONE_MAX_LENGTH,
1416
+ description: LISTING_DESCRIPTION_MAX_LENGTH
1417
+ };
1418
+ for (const [fieldName, maxLength] of Object.entries(limits)) {
1419
+ const value = payload[fieldName];
1420
+ if (value === void 0 || value === null) continue;
1421
+ if (typeof value !== "string") {
1422
+ throw new SiglumeClientError(`AppManifest.${fieldName} must be a string when provided.`);
1423
+ }
1424
+ if (Array.from(value).length > maxLength) {
1425
+ throw new SiglumeClientError(`AppManifest.${fieldName} must be at most ${maxLength} characters.`);
1426
+ }
1427
+ }
1428
+ }
1407
1429
  function buildToolManualQualityReport(payload) {
1408
1430
  const qualityBlock = isRecord(payload.quality) ? payload.quality : payload;
1409
1431
  const issues = [];
@@ -1961,139 +1983,6 @@ function parseInstalledToolReceiptStep(data) {
1961
1983
  raw: { ...data }
1962
1984
  };
1963
1985
  }
1964
- function toRecordList(value) {
1965
- return Array.isArray(value) ? value.filter((item) => isRecord(item)).map((item) => ({ ...item })) : [];
1966
- }
1967
- function parsePartnerDashboard(data) {
1968
- return {
1969
- partner_id: String(data.partner_id ?? data.user_id ?? ""),
1970
- company_name: stringOrNull(data.company_name) ?? void 0,
1971
- plan: stringOrNull(data.plan) ?? void 0,
1972
- plan_label: stringOrNull(data.plan_label) ?? void 0,
1973
- month_bytes_used: Math.trunc(Number(data.month_bytes_used ?? 0)),
1974
- month_bytes_limit: Math.trunc(Number(data.month_bytes_limit ?? 0)),
1975
- month_usage_pct: Number(data.month_usage_pct ?? 0),
1976
- total_source_items: Math.trunc(Number(data.total_source_items ?? 0)),
1977
- has_billing: Boolean(data.has_billing ?? false),
1978
- has_subscription: Boolean(data.has_subscription ?? false),
1979
- raw: { ...data }
1980
- };
1981
- }
1982
- function parsePartnerUsage(data) {
1983
- return {
1984
- plan: stringOrNull(data.plan) ?? void 0,
1985
- month_bytes_used: Math.trunc(Number(data.month_bytes_used ?? 0)),
1986
- month_bytes_limit: Math.trunc(Number(data.month_bytes_limit ?? 0)),
1987
- month_bytes_remaining: Math.trunc(Number(data.month_bytes_remaining ?? 0)),
1988
- month_usage_pct: Number(data.month_usage_pct ?? 0),
1989
- raw: { ...data }
1990
- };
1991
- }
1992
- function parsePartnerApiKey(data) {
1993
- return {
1994
- credential_id: String(data.credential_id ?? data.id ?? ""),
1995
- name: stringOrNull(data.name) ?? void 0,
1996
- key_id: stringOrNull(data.key_id) ?? void 0,
1997
- allowed_source_types: Array.isArray(data.allowed_source_types) ? data.allowed_source_types.filter((item) => typeof item === "string") : [],
1998
- last_used_at: stringOrNull(data.last_used_at) ?? void 0,
1999
- created_at: stringOrNull(data.created_at) ?? void 0,
2000
- revoked: Boolean(data.revoked ?? false),
2001
- raw: { ...data }
2002
- };
2003
- }
2004
- function parsePartnerApiKeyHandle(data) {
2005
- const raw = Object.fromEntries(
2006
- Object.entries(data).filter(([key]) => key !== "ingest_key" && key !== "full_key")
2007
- );
2008
- return {
2009
- credential_id: String(raw.credential_id ?? raw.id ?? ""),
2010
- name: stringOrNull(raw.name) ?? void 0,
2011
- key_id: stringOrNull(raw.key_id) ?? void 0,
2012
- allowed_source_types: Array.isArray(raw.allowed_source_types) ? raw.allowed_source_types.filter((item) => typeof item === "string") : [],
2013
- masked_key_hint: stringOrNull(raw.masked_key_hint) ?? void 0,
2014
- raw
2015
- };
2016
- }
2017
- function parseAdsBilling(data) {
2018
- return {
2019
- currency: stringOrNull(data.currency) ?? void 0,
2020
- billing_mode: stringOrNull(data.billing_mode) ?? void 0,
2021
- month_spend_jpy: Math.trunc(Number(data.month_spend_jpy ?? 0)),
2022
- month_spend_usd: Math.trunc(Number(data.month_spend_usd ?? 0)),
2023
- all_time_spend_jpy: Math.trunc(Number(data.all_time_spend_jpy ?? 0)),
2024
- all_time_spend_usd: Math.trunc(Number(data.all_time_spend_usd ?? 0)),
2025
- total_impressions: Math.trunc(Number(data.total_impressions ?? 0)),
2026
- total_replies: Math.trunc(Number(data.total_replies ?? 0)),
2027
- has_billing: Boolean(data.has_billing ?? false),
2028
- has_subscription: Boolean(data.has_subscription ?? false),
2029
- invoices: toRecordList(data.invoices),
2030
- wallet: isRecord(data.wallet) ? { ...data.wallet } : null,
2031
- balances: toRecordList(data.balances),
2032
- supported_tokens: toRecordList(data.supported_tokens),
2033
- funding_instructions: isRecord(data.funding_instructions) ? { ...data.funding_instructions } : null,
2034
- mandate: isRecord(data.mandate) ? parsePlanWeb3Mandate(data.mandate) : null,
2035
- raw: { ...data }
2036
- };
2037
- }
2038
- function parseAdsBillingSettlement(data) {
2039
- return {
2040
- status: stringOrNull(data.status) ?? void 0,
2041
- message: stringOrNull(data.message ?? data.detail) ?? void 0,
2042
- settles_automatically: typeof data.settles_automatically === "boolean" ? data.settles_automatically : typeof data.auto_settles === "boolean" ? data.auto_settles : void 0,
2043
- cycle_key: stringOrNull(data.cycle_key) ?? void 0,
2044
- settled_at: stringOrNull(data.settled_at) ?? void 0,
2045
- raw: { ...data }
2046
- };
2047
- }
2048
- function parseAdsProfile(data) {
2049
- return {
2050
- has_profile: Boolean(data.has_profile ?? false),
2051
- company_name: stringOrNull(data.company_name) ?? void 0,
2052
- ad_currency: stringOrNull(data.ad_currency) ?? void 0,
2053
- has_billing: Boolean(data.has_billing ?? false),
2054
- raw: { ...data }
2055
- };
2056
- }
2057
- function parseAdsCampaign(data) {
2058
- return {
2059
- campaign_id: String(data.campaign_id ?? data.id ?? ""),
2060
- name: stringOrNull(data.name) ?? void 0,
2061
- target_url: stringOrNull(data.target_url) ?? void 0,
2062
- content_brief: stringOrNull(data.content_brief) ?? void 0,
2063
- target_topics: Array.isArray(data.target_topics) ? data.target_topics.filter((item) => typeof item === "string") : [],
2064
- posting_interval_minutes: Math.trunc(Number(data.posting_interval_minutes ?? 360)),
2065
- max_posts_per_day: Math.trunc(Number(data.max_posts_per_day ?? 4)),
2066
- currency: stringOrNull(data.currency) ?? void 0,
2067
- monthly_budget_jpy: Math.trunc(Number(data.monthly_budget_jpy ?? 0)),
2068
- cpm_jpy: Math.trunc(Number(data.cpm_jpy ?? 0)),
2069
- cpr_jpy: Math.trunc(Number(data.cpr_jpy ?? 0)),
2070
- monthly_budget_usd: Math.trunc(Number(data.monthly_budget_usd ?? 0)),
2071
- cpm_usd: Math.trunc(Number(data.cpm_usd ?? 0)),
2072
- cpr_usd: Math.trunc(Number(data.cpr_usd ?? 0)),
2073
- status: String(data.status ?? "active").trim().toLowerCase() || "active",
2074
- month_spend_jpy: Math.trunc(Number(data.month_spend_jpy ?? 0)),
2075
- month_spend_usd: Math.trunc(Number(data.month_spend_usd ?? 0)),
2076
- total_posts: Math.trunc(Number(data.total_posts ?? 0)),
2077
- total_impressions: Math.trunc(Number(data.total_impressions ?? 0)),
2078
- total_replies: Math.trunc(Number(data.total_replies ?? 0)),
2079
- next_post_at: stringOrNull(data.next_post_at) ?? void 0,
2080
- created_at: stringOrNull(data.created_at) ?? void 0,
2081
- raw: { ...data }
2082
- };
2083
- }
2084
- function parseAdsCampaignPost(data) {
2085
- return {
2086
- post_id: String(data.post_id ?? data.id ?? ""),
2087
- content_id: stringOrNull(data.content_id) ?? void 0,
2088
- cost_jpy: Math.trunc(Number(data.cost_jpy ?? 0)),
2089
- cost_usd: Math.trunc(Number(data.cost_usd ?? 0)),
2090
- impressions: Math.trunc(Number(data.impressions ?? 0)),
2091
- replies: Math.trunc(Number(data.replies ?? 0)),
2092
- status: stringOrNull(data.status) ?? void 0,
2093
- created_at: stringOrNull(data.created_at) ?? void 0,
2094
- raw: { ...data }
2095
- };
2096
- }
2097
1986
  function parseWorksCategory(data) {
2098
1987
  return {
2099
1988
  key: String(data.key ?? ""),
@@ -2592,7 +2481,7 @@ function cloneJsonLike(value) {
2592
2481
  }
2593
2482
  return value;
2594
2483
  }
2595
- var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, MINIMUM_JPY_OPERATION_PRICE_CURRENCIES, CursorPageResult, SiglumeClient;
2484
+ var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, MINIMUM_JPY_OPERATION_PRICE_CURRENCIES, LISTING_SHORT_DESCRIPTION_MAX_LENGTH, LISTING_JOB_TO_BE_DONE_MAX_LENGTH, LISTING_DESCRIPTION_MAX_LENGTH, CursorPageResult, SiglumeClient;
2596
2485
  var init_client = __esm({
2597
2486
  "src/client.ts"() {
2598
2487
  "use strict";
@@ -2605,6 +2494,9 @@ var init_client = __esm({
2605
2494
  DEFAULT_SIGLUME_API_BASE = "https://siglume.com/v1";
2606
2495
  RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
2607
2496
  MINIMUM_JPY_OPERATION_PRICE_CURRENCIES = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
2497
+ LISTING_SHORT_DESCRIPTION_MAX_LENGTH = 60;
2498
+ LISTING_JOB_TO_BE_DONE_MAX_LENGTH = 240;
2499
+ LISTING_DESCRIPTION_MAX_LENGTH = 1e3;
2608
2500
  CursorPageResult = class {
2609
2501
  items;
2610
2502
  next_cursor;
@@ -2758,6 +2650,7 @@ var init_client = __esm({
2758
2650
  if (payload.pricing_plan !== void 0) {
2759
2651
  validatePricingPlanFloor(payload.pricing_plan, currency);
2760
2652
  }
2653
+ validateListingTextLengths(payload);
2761
2654
  const priceModel = String(payload.price_model ?? "free").trim().toLowerCase();
2762
2655
  if ((priceModel === "usage_based" || priceModel === "per_action") && !pricingPlanHasItems(payload.pricing_plan)) {
2763
2656
  throw new SiglumeClientError("AppManifest.pricing_plan.items is required for usage_based/per_action pricing.");
@@ -3900,115 +3793,6 @@ var init_client = __esm({
3900
3793
  );
3901
3794
  return Array.isArray(data.result) ? data.result.filter((item) => isRecord(item)).map((item) => parseInstalledToolReceiptStep(item)) : [];
3902
3795
  }
3903
- async get_partner_dashboard(options = {}) {
3904
- const execution = await this.execute_owner_operation(
3905
- await this.resolveOwnerOperationAgentId(options.agent_id),
3906
- "partner.dashboard.get",
3907
- {},
3908
- { lang: options.lang }
3909
- );
3910
- return parsePartnerDashboard(execution.result);
3911
- }
3912
- async get_partner_usage(options = {}) {
3913
- const execution = await this.execute_owner_operation(
3914
- await this.resolveOwnerOperationAgentId(options.agent_id),
3915
- "partner.usage.get",
3916
- {},
3917
- { lang: options.lang }
3918
- );
3919
- return parsePartnerUsage(execution.result);
3920
- }
3921
- async list_partner_api_keys(options = {}) {
3922
- const execution = await this.execute_owner_operation(
3923
- await this.resolveOwnerOperationAgentId(options.agent_id),
3924
- "partner.keys.list",
3925
- {},
3926
- { lang: options.lang }
3927
- );
3928
- return Array.isArray(execution.result.keys) ? execution.result.keys.filter((item) => isRecord(item)).map((item) => parsePartnerApiKey(item)) : [];
3929
- }
3930
- async create_partner_api_key(options = {}) {
3931
- const payload = {};
3932
- if (options.name !== void 0) {
3933
- const normalizedName = String(options.name).trim();
3934
- if (!normalizedName) {
3935
- throw new SiglumeClientError("name cannot be empty.");
3936
- }
3937
- payload.name = normalizedName;
3938
- }
3939
- if (options.allowed_source_types !== void 0) {
3940
- if (!Array.isArray(options.allowed_source_types)) {
3941
- throw new SiglumeClientError("allowed_source_types must be a list of strings.");
3942
- }
3943
- payload.allowed_source_types = options.allowed_source_types.flatMap((item) => {
3944
- if (typeof item !== "string") {
3945
- throw new SiglumeClientError("allowed_source_types must contain only strings.");
3946
- }
3947
- const normalizedItem = item.trim();
3948
- return normalizedItem ? [normalizedItem] : [];
3949
- });
3950
- }
3951
- const execution = await this.execute_owner_operation(
3952
- await this.resolveOwnerOperationAgentId(options.agent_id),
3953
- "partner.keys.create",
3954
- payload,
3955
- { lang: options.lang }
3956
- );
3957
- return parsePartnerApiKeyHandle(execution.result);
3958
- }
3959
- async get_ads_billing(options = {}) {
3960
- const payload = {};
3961
- if (options.rail !== void 0 && String(options.rail).trim()) {
3962
- payload.rail = String(options.rail).trim().toLowerCase();
3963
- }
3964
- const execution = await this.execute_owner_operation(
3965
- await this.resolveOwnerOperationAgentId(options.agent_id),
3966
- "ads.billing.get",
3967
- payload,
3968
- { lang: options.lang }
3969
- );
3970
- return parseAdsBilling(execution.result);
3971
- }
3972
- async settle_ads_billing(options = {}) {
3973
- const execution = await this.execute_owner_operation(
3974
- await this.resolveOwnerOperationAgentId(options.agent_id),
3975
- "ads.billing.settle",
3976
- {},
3977
- { lang: options.lang }
3978
- );
3979
- return parseAdsBillingSettlement(execution.result);
3980
- }
3981
- async get_ads_profile(options = {}) {
3982
- const execution = await this.execute_owner_operation(
3983
- await this.resolveOwnerOperationAgentId(options.agent_id),
3984
- "ads.profile.get",
3985
- {},
3986
- { lang: options.lang }
3987
- );
3988
- return parseAdsProfile(execution.result);
3989
- }
3990
- async list_ads_campaigns(options = {}) {
3991
- const execution = await this.execute_owner_operation(
3992
- await this.resolveOwnerOperationAgentId(options.agent_id),
3993
- "ads.campaigns.list",
3994
- {},
3995
- { lang: options.lang }
3996
- );
3997
- return Array.isArray(execution.result.campaigns) ? execution.result.campaigns.filter((item) => isRecord(item)).map((item) => parseAdsCampaign(item)) : [];
3998
- }
3999
- async list_ads_campaign_posts(campaign_id, options = {}) {
4000
- const normalizedCampaignId = String(campaign_id ?? "").trim();
4001
- if (!normalizedCampaignId) {
4002
- throw new SiglumeClientError("campaign_id is required.");
4003
- }
4004
- const execution = await this.execute_owner_operation(
4005
- await this.resolveOwnerOperationAgentId(options.agent_id),
4006
- "ads.campaign_posts.list",
4007
- { campaign_id: normalizedCampaignId },
4008
- { lang: options.lang }
4009
- );
4010
- return Array.isArray(execution.result.posts) ? execution.result.posts.filter((item) => isRecord(item)).map((item) => parseAdsCampaignPost(item)) : [];
4011
- }
4012
3796
  // `market.proposals.*` currently rides on the public owner-operation execute
4013
3797
  // route. Read helpers return typed proposal records; guarded mutations return
4014
3798
  // the approval envelope without treating it as an error.
@@ -5938,12 +5722,15 @@ function validate_tool_manual(manualInput) {
5938
5722
  pushError("INVALID_TOOL_NAME", "tool_name must be alphanumeric + underscore, 3-64 chars", "tool_name");
5939
5723
  }
5940
5724
  for (const [fieldName, minLength, maxLength] of [
5941
- ["job_to_be_done", 10, 500],
5725
+ ["job_to_be_done", 10, 240],
5942
5726
  ["summary_for_model", 10, 300]
5943
5727
  ]) {
5944
5728
  const value = manual[fieldName];
5945
- if (typeof value === "string" && (value.length < minLength || value.length > maxLength)) {
5946
- pushError("INVALID_TYPE", `${fieldName} must be ${minLength}-${maxLength} characters`, fieldName);
5729
+ if (typeof value === "string") {
5730
+ const length = Array.from(value).length;
5731
+ if (length < minLength || length > maxLength) {
5732
+ pushError("INVALID_TYPE", `${fieldName} must be ${minLength}-${maxLength} characters`, fieldName);
5733
+ }
5947
5734
  }
5948
5735
  }
5949
5736
  const triggerConditions = manual.trigger_conditions;
@@ -7131,8 +6918,12 @@ function buildRuntimeValidationTemplate(toolManual) {
7131
6918
  healthcheck_url: "https://api.example.com/health",
7132
6919
  invoke_url: "https://api.example.com/invoke",
7133
6920
  invoke_method: "POST",
7134
- test_auth_header_name: "X-Siglume-Review-Key",
7135
- test_auth_header_value: "replace-with-dedicated-review-key",
6921
+ // Shared secret Siglume attaches when it calls invoke_url at both
6922
+ // registration validation and production runtime. Use a strong random
6923
+ // value, keep it in the Git-ignored runtime_validation.json, and rotate it
6924
+ // if it leaks. (legacy aliases: test_auth_header_name/value)
6925
+ runtime_auth_header_name: "X-Siglume-Auth",
6926
+ runtime_auth_header_value: "replace-with-strong-random-runtime-auth-secret",
7136
6927
  request_payload: requestPayload,
7137
6928
  expected_response_fields: expectedFields.length > 0 ? expectedFields : ["summary"],
7138
6929
  timeout_seconds: 10
@@ -7437,8 +7228,6 @@ function runtimePlaceholderIssues(runtimeValidation) {
7437
7228
  "public_base_url",
7438
7229
  "healthcheck_url",
7439
7230
  "invoke_url",
7440
- "test_auth_header_name",
7441
- "test_auth_header_value",
7442
7231
  "expected_response_fields"
7443
7232
  ]) {
7444
7233
  if (!runtimeValidation[fieldName]) {
@@ -7451,9 +7240,19 @@ function runtimePlaceholderIssues(runtimeValidation) {
7451
7240
  issues.push(`runtime_validation.${fieldName} must be replaced with your public production URL`);
7452
7241
  }
7453
7242
  }
7454
- const authValue = String(runtimeValidation.test_auth_header_value ?? "").trim();
7243
+ const authName = String(
7244
+ runtimeValidation.runtime_auth_header_name || runtimeValidation.test_auth_header_name || ""
7245
+ ).trim();
7246
+ if (!authName) {
7247
+ issues.push("runtime_validation.runtime_auth_header_name is required");
7248
+ }
7249
+ const authValue = String(
7250
+ runtimeValidation.runtime_auth_header_value || runtimeValidation.test_auth_header_value || ""
7251
+ ).trim();
7455
7252
  if (!authValue || authValue.startsWith("replace-with-")) {
7456
- issues.push("runtime_validation.test_auth_header_value must be a dedicated review secret, not a placeholder");
7253
+ issues.push(
7254
+ "runtime_validation.runtime_auth_header_value must be a strong, dedicated runtime auth secret, not a placeholder"
7255
+ );
7457
7256
  }
7458
7257
  const requestPayload = runtimeValidation.request_payload ?? runtimeValidation.test_request_body ?? runtimeValidation.runtime_sample ?? runtimeValidation.sample_request_payload ?? runtimeValidation.runtime_sample_request;
7459
7258
  if (!isRecord(requestPayload)) {
@@ -7468,7 +7267,7 @@ function runtimePlaceholderIssues(runtimeValidation) {
7468
7267
  function ensureRuntimeValidationReady(project) {
7469
7268
  if (!project.runtime_validation) {
7470
7269
  throw new SiglumeProjectError(
7471
- "runtime_validation.json is required for `siglume register`. Create it with public_base_url, healthcheck_url, invoke_url, dedicated review auth header, request_payload, and expected_response_fields."
7270
+ "runtime_validation.json is required for `siglume register`. Create it with public_base_url, healthcheck_url, invoke_url, runtime auth header (runtime_auth_header_name/value), request_payload, and expected_response_fields."
7472
7271
  );
7473
7272
  }
7474
7273
  const issues = runtimePlaceholderIssues(project.runtime_validation);
@@ -8157,19 +7956,19 @@ function operationReadmeTemplate(operation, manifest, warning) {
8157
7956
  "- `stubs.ts`: mock fallback used when `SIGLUME_API_KEY` is not set",
8158
7957
  "- `manifest.json`: reviewable manifest snapshot",
8159
7958
  "- `tool_manual.json`: machine-generated ToolManual scaffold",
8160
- "- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
7959
+ "- `runtime_validation.json`: local public endpoint + runtime auth header checks used by auto-register",
8161
7960
  "- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
8162
- "- `.gitignore`: keeps runtime review keys out of Git",
7961
+ "- `.gitignore`: keeps the runtime auth secret out of Git",
8163
7962
  "- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
8164
7963
  "",
8165
7964
  "Before registering, replace all generated placeholders:",
8166
7965
  "- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
8167
7966
  "- Replace `support_contact` with a real support email address or public support URL.",
8168
7967
  "- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
8169
- "- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
7968
+ "- In the local `runtime_validation.json`, replace the public URL and runtime auth header placeholders (runtime_auth_header_name/value).",
8170
7969
  "- If the API uses external OAuth, implement that flow in your API runtime and keep user tokens outside Siglume.",
8171
- "- Do not commit real review keys or external-provider secrets; the generated `.gitignore` excludes local secret files.",
8172
- "- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
7970
+ "- Do not commit the real runtime auth secret or external-provider secrets; the generated `.gitignore` excludes local secret files.",
7971
+ "- Because `runtime_validation.json` is ignored, GitHub samples do not commit runtime auth secret values.",
8173
7972
  "",
8174
7973
  "## Commands",
8175
7974
  "",
@@ -8238,7 +8037,7 @@ function apiUsageDocsTemplate(manifest) {
8238
8037
  }
8239
8038
  function generatedGitignore() {
8240
8039
  return [
8241
- "# Local secrets and registration-only runtime checks.",
8040
+ "# Local secrets (incl. the runtime auth shared secret) and runtime checks.",
8242
8041
  ".env",
8243
8042
  ".env.*",
8244
8043
  "!.env.example",
@@ -8722,16 +8521,16 @@ function readmeTemplate(template) {
8722
8521
  "- `tool_manual.json`: editable ToolManual draft for validation and registration",
8723
8522
  "- `runtime_validation.json`: local live API smoke-test contract used during registration",
8724
8523
  "- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
8725
- "- `.gitignore`: keeps runtime review keys out of Git",
8524
+ "- `.gitignore`: keeps the runtime auth secret out of Git",
8726
8525
  "",
8727
8526
  "Before registering, replace all generated placeholders:",
8728
8527
  "- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
8729
8528
  "- Replace `support_contact` with a real support email address or public support URL.",
8730
8529
  "- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
8731
- "- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
8530
+ "- In the local `runtime_validation.json`, replace the public URL and runtime auth header placeholders (runtime_auth_header_name/value).",
8732
8531
  "- If the API uses external OAuth, implement that flow in your API runtime and keep user tokens outside Siglume.",
8733
- "- Do not commit real review keys or external-provider secrets; the generated `.gitignore` excludes local secret files.",
8734
- "- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
8532
+ "- Do not commit the real runtime auth secret or external-provider secrets; the generated `.gitignore` excludes local secret files.",
8533
+ "- Because `runtime_validation.json` is ignored, GitHub samples do not commit runtime auth secret values.",
8735
8534
  "",
8736
8535
  "Suggested workflow:",
8737
8536
  "",