@siglume/api-sdk 0.10.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -176,6 +176,61 @@ var init_utils = __esm({
176
176
  }
177
177
  });
178
178
 
179
+ // src/types.ts
180
+ var PermissionClass, ApprovalMode, Environment, PriceModel, AppCategory, MINIMUM_JPY_OPERATION_PRICE_MINOR, ToolManualPermissionClass, SettlementMode;
181
+ var init_types = __esm({
182
+ "src/types.ts"() {
183
+ "use strict";
184
+ PermissionClass = {
185
+ READ_ONLY: "read-only",
186
+ ACTION: "action",
187
+ PAYMENT: "payment",
188
+ /** @deprecated Use READ_ONLY. Behaves identically. */
189
+ RECOMMENDATION: "recommendation"
190
+ };
191
+ ApprovalMode = {
192
+ AUTO: "auto",
193
+ BUDGET_BOUNDED: "budget-bounded",
194
+ ALWAYS_ASK: "always-ask",
195
+ DENY: "deny"
196
+ };
197
+ Environment = {
198
+ SANDBOX: "sandbox",
199
+ LIVE: "live"
200
+ };
201
+ PriceModel = {
202
+ FREE: "free",
203
+ SUBSCRIPTION: "subscription",
204
+ ONE_TIME: "one_time",
205
+ BUNDLE: "bundle",
206
+ USAGE_BASED: "usage_based",
207
+ PER_ACTION: "per_action"
208
+ };
209
+ AppCategory = {
210
+ COMMERCE: "commerce",
211
+ BOOKING: "booking",
212
+ CRM: "crm",
213
+ FINANCE: "finance",
214
+ DOCUMENT: "document",
215
+ COMMUNICATION: "communication",
216
+ MONITORING: "monitoring",
217
+ OTHER: "other"
218
+ };
219
+ MINIMUM_JPY_OPERATION_PRICE_MINOR = 15;
220
+ ToolManualPermissionClass = {
221
+ READ_ONLY: "read_only",
222
+ ACTION: "action",
223
+ PAYMENT: "payment"
224
+ };
225
+ SettlementMode = {
226
+ STRIPE_CHECKOUT: "stripe_checkout",
227
+ STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
228
+ POLYGON_MANDATE: "polygon_mandate",
229
+ EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
230
+ };
231
+ }
232
+ });
233
+
179
234
  // src/webhooks.ts
180
235
  function isRecord2(value) {
181
236
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1297,6 +1352,58 @@ function validateSaveDataSchema(schema, fieldName) {
1297
1352
  }
1298
1353
  }
1299
1354
  }
1355
+ function validatePricingPlanFloor(plan, defaultCurrency) {
1356
+ if (plan === void 0 || plan === null) {
1357
+ return;
1358
+ }
1359
+ if (!isRecord(plan)) {
1360
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
1361
+ }
1362
+ const items = plan.items;
1363
+ if (items === void 0 || items === null) {
1364
+ return;
1365
+ }
1366
+ if (!Array.isArray(items)) {
1367
+ throw new SiglumeClientError("AppManifest.pricing_plan.items must be an array when provided.");
1368
+ }
1369
+ const planCurrency = String(plan.currency ?? defaultCurrency ?? "").trim().toUpperCase();
1370
+ const seenKeys = /* @__PURE__ */ new Set();
1371
+ items.forEach((item, index) => {
1372
+ if (!isRecord(item)) {
1373
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}] must be an object.`);
1374
+ }
1375
+ const itemKey = String(
1376
+ item.key ?? item.operation ?? item.operation_key ?? item.request_type ?? item.receipt_code ?? item.action ?? ""
1377
+ ).trim();
1378
+ if (!itemKey) {
1379
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key is required.`);
1380
+ }
1381
+ if (seenKeys.has(itemKey)) {
1382
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key duplicates ${itemKey}.`);
1383
+ }
1384
+ seenKeys.add(itemKey);
1385
+ const amountRaw = item.price_minor ?? item.amount_minor ?? item.cost_minor ?? item.value_minor;
1386
+ if (amountRaw === void 0 || amountRaw === null) {
1387
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor is required.`);
1388
+ }
1389
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
1390
+ if (!Number.isInteger(amountMinor)) {
1391
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be an integer.`);
1392
+ }
1393
+ if (amountMinor < 0) {
1394
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be zero or positive.`);
1395
+ }
1396
+ const currency = String(item.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
1397
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
1398
+ throw new SiglumeClientError(
1399
+ `AppManifest.pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing.`
1400
+ );
1401
+ }
1402
+ });
1403
+ }
1404
+ function pricingPlanHasItems(plan) {
1405
+ return isRecord(plan) && Array.isArray(plan.items) && plan.items.length > 0;
1406
+ }
1300
1407
  function buildToolManualQualityReport(payload) {
1301
1408
  const qualityBlock = isRecord(payload.quality) ? payload.quality : payload;
1302
1409
  const issues = [];
@@ -1372,6 +1479,7 @@ function buildUrl(baseUrl, path, params) {
1372
1479
  }
1373
1480
  function parseListing(data) {
1374
1481
  const metadata = isRecord(data.metadata) ? data.metadata : {};
1482
+ const pricing_plan = isRecord(data.pricing_plan) ? data.pricing_plan : isRecord(metadata.pricing_plan) ? metadata.pricing_plan : null;
1375
1483
  const persistence = isRecord(data.persistence) ? data.persistence : isRecord(metadata.persistence) ? metadata.persistence : {};
1376
1484
  return {
1377
1485
  listing_id: String(data.listing_id ?? data.id ?? ""),
@@ -1385,6 +1493,7 @@ function parseListing(data) {
1385
1493
  dry_run_supported: Boolean(data.dry_run_supported ?? false),
1386
1494
  price_model: stringOrNull(data.price_model),
1387
1495
  price_value_minor: Number(data.price_value_minor ?? 0),
1496
+ pricing_plan,
1388
1497
  currency: String(data.currency ?? "USD"),
1389
1498
  allow_free_trial: Boolean(data.allow_free_trial ?? false),
1390
1499
  free_trial_duration_days: Number(data.free_trial_duration_days ?? 30),
@@ -1459,18 +1568,6 @@ function parseBundleMember(data) {
1459
1568
  link_id: stringOrNull(data.link_id)
1460
1569
  };
1461
1570
  }
1462
- function parseConnectedAccountLifecycle(data) {
1463
- return {
1464
- connected_account_id: String(data.connected_account_id ?? ""),
1465
- provider_key: String(data.provider_key ?? ""),
1466
- expires_at: stringOrNull(data.expires_at),
1467
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((s) => typeof s === "string") : [],
1468
- refreshed_at: stringOrNull(data.refreshed_at),
1469
- connection_status: stringOrNull(data.connection_status),
1470
- provider_revoked: typeof data.provider_revoked === "boolean" ? data.provider_revoked : null,
1471
- revoked_at: stringOrNull(data.revoked_at)
1472
- };
1473
- }
1474
1571
  function parseBundle(data) {
1475
1572
  const membersRaw = Array.isArray(data.members) ? data.members : [];
1476
1573
  return {
@@ -1549,21 +1646,6 @@ function parseBinding(data) {
1549
1646
  raw: { ...data }
1550
1647
  };
1551
1648
  }
1552
- function parseConnectedAccount(data) {
1553
- return {
1554
- connected_account_id: String(data.connected_account_id ?? data.id ?? ""),
1555
- provider_key: String(data.provider_key ?? ""),
1556
- account_role: String(data.account_role ?? ""),
1557
- display_name: stringOrNull(data.display_name),
1558
- environment: stringOrNull(data.environment),
1559
- connection_status: stringOrNull(data.connection_status),
1560
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((item) => typeof item === "string") : [],
1561
- metadata: toRecord(data.metadata),
1562
- created_at: stringOrNull(data.created_at),
1563
- updated_at: stringOrNull(data.updated_at),
1564
- raw: { ...data }
1565
- };
1566
- }
1567
1649
  function parseSupportCase(data) {
1568
1650
  return {
1569
1651
  support_case_id: String(data.support_case_id ?? data.id ?? ""),
@@ -2509,10 +2591,11 @@ function cloneJsonLike(value) {
2509
2591
  }
2510
2592
  return value;
2511
2593
  }
2512
- var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, CursorPageResult, SiglumeClient;
2594
+ var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, MINIMUM_JPY_OPERATION_PRICE_CURRENCIES, CursorPageResult, SiglumeClient;
2513
2595
  var init_client = __esm({
2514
2596
  "src/client.ts"() {
2515
2597
  "use strict";
2598
+ init_types();
2516
2599
  init_errors();
2517
2600
  init_webhooks();
2518
2601
  init_web3();
@@ -2520,6 +2603,7 @@ var init_client = __esm({
2520
2603
  init_utils();
2521
2604
  DEFAULT_SIGLUME_API_BASE = "https://siglume.com/v1";
2522
2605
  RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
2606
+ MINIMUM_JPY_OPERATION_PRICE_CURRENCIES = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
2523
2607
  CursorPageResult = class {
2524
2608
  items;
2525
2609
  next_cursor;
@@ -2602,13 +2686,6 @@ var init_client = __esm({
2602
2686
  if (options.runtime_validation) {
2603
2687
  payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
2604
2688
  }
2605
- if (options.oauth_credentials) {
2606
- payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
2607
- items: options.oauth_credentials.map(
2608
- (item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
2609
- )
2610
- } : coerceMapping(options.oauth_credentials, "oauth_credentials");
2611
- }
2612
2689
  if (options.source_context) {
2613
2690
  payload.source_context = coerceMapping(options.source_context, "source_context");
2614
2691
  }
@@ -2634,6 +2711,7 @@ var init_client = __esm({
2634
2711
  "jurisdiction",
2635
2712
  "price_model",
2636
2713
  "price_value_minor",
2714
+ "pricing_plan",
2637
2715
  "currency",
2638
2716
  "allow_free_trial",
2639
2717
  "free_trial_duration_days",
@@ -2650,6 +2728,9 @@ var init_client = __esm({
2650
2728
  payload[fieldName] = value;
2651
2729
  }
2652
2730
  }
2731
+ if (payload.pricing_plan !== void 0 && (typeof payload.pricing_plan !== "object" || Array.isArray(payload.pricing_plan))) {
2732
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
2733
+ }
2653
2734
  if (payload.store_vertical === void 0 || payload.store_vertical === null) {
2654
2735
  throw new SiglumeClientError(
2655
2736
  "AppManifest.store_vertical is required. Choose 'api' for normal API Store listings or 'game' for API games."
@@ -2665,6 +2746,13 @@ var init_client = __esm({
2665
2746
  throw new SiglumeClientError(`AppManifest.currency must be 'USD' or 'JPY'. Got ${String(payload.currency)}.`);
2666
2747
  }
2667
2748
  payload.currency = currency;
2749
+ if (payload.pricing_plan !== void 0) {
2750
+ validatePricingPlanFloor(payload.pricing_plan, currency);
2751
+ }
2752
+ const priceModel = String(payload.price_model ?? "free").trim().toLowerCase();
2753
+ if ((priceModel === "usage_based" || priceModel === "per_action") && !pricingPlanHasItems(payload.pricing_plan)) {
2754
+ throw new SiglumeClientError("AppManifest.pricing_plan.items is required for usage_based/per_action pricing.");
2755
+ }
2668
2756
  if (payload.allow_free_trial === void 0 || payload.allow_free_trial === null) {
2669
2757
  throw new SiglumeClientError(
2670
2758
  "AppManifest.allow_free_trial is required. Pass true to offer a Plus/Pro buyer free trial or false to disable trials."
@@ -2738,7 +2826,6 @@ var init_client = __esm({
2738
2826
  auto_manifest: toRecord(data.auto_manifest),
2739
2827
  confidence: toRecord(data.confidence),
2740
2828
  validation_report: toRecord(data.validation_report),
2741
- oauth_status: toRecord(data.oauth_status),
2742
2829
  review_url: stringOrNull(data.review_url),
2743
2830
  trace_id: meta.trace_id,
2744
2831
  request_id: meta.request_id
@@ -2914,66 +3001,9 @@ var init_client = __esm({
2914
3001
  return parseBundle(data);
2915
3002
  }
2916
3003
  // ----- end bundles -------------------------------------------------------
2917
- // ----- Connected accounts (v0.7 track 3) ---------------------------------
2918
- // `resolve()` is intentionally NOT wrapped: runtime-only, never over the wire.
2919
- async start_connected_account_oauth(input) {
2920
- const body = {
2921
- listing_id: input.listing_id,
2922
- redirect_uri: input.redirect_uri
2923
- };
2924
- if (input.scopes !== void 0) body.scopes = input.scopes;
2925
- if (input.account_role !== void 0) body.account_role = input.account_role;
2926
- const [data] = await this.request("POST", "/me/connected-accounts/oauth/authorize", {
2927
- json_body: body
2928
- });
2929
- return {
2930
- authorize_url: String(data.authorize_url ?? ""),
2931
- state: String(data.state ?? ""),
2932
- provider_key: String(data.provider_key ?? ""),
2933
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((s) => typeof s === "string") : [],
2934
- pkce_method: stringOrNull(data.pkce_method)
2935
- };
2936
- }
2937
- async complete_connected_account_oauth(input) {
2938
- const [data] = await this.request("POST", "/me/connected-accounts/oauth/callback", {
2939
- json_body: { state: input.state, code: input.code }
2940
- });
2941
- return { ...data };
2942
- }
2943
- async refresh_connected_account(account_id) {
2944
- const [data] = await this.request("POST", `/me/connected-accounts/${account_id}/refresh`);
2945
- return parseConnectedAccountLifecycle(data);
2946
- }
2947
- async revoke_connected_account(account_id) {
2948
- const [data] = await this.request("POST", `/me/connected-accounts/${account_id}/revoke`);
2949
- return parseConnectedAccountLifecycle(data);
2950
- }
2951
- async set_listing_oauth_credentials(listing_id, input) {
2952
- const body = {
2953
- provider_key: input.provider_key,
2954
- client_id: input.client_id,
2955
- client_secret: input.client_secret,
2956
- authorize_url: input.authorize_url,
2957
- token_url: input.token_url
2958
- };
2959
- if (input.revoke_url !== void 0) body.revoke_url = input.revoke_url;
2960
- if (input.display_name !== void 0) body.display_name = input.display_name;
2961
- if (input.scope_separator !== void 0) body.scope_separator = input.scope_separator;
2962
- if (input.token_endpoint_auth !== void 0) body.token_endpoint_auth = input.token_endpoint_auth;
2963
- if (input.pkce_required !== void 0) body.pkce_required = input.pkce_required;
2964
- if (input.refresh_supported !== void 0) body.refresh_supported = input.refresh_supported;
2965
- if (input.available_scopes !== void 0) body.available_scopes = input.available_scopes;
2966
- if (input.required_scopes !== void 0) body.required_scopes = input.required_scopes;
2967
- const [data] = await this.request("PUT", `/market/capabilities/${listing_id}/oauth-credentials`, {
2968
- json_body: body
2969
- });
2970
- return { ...data };
2971
- }
2972
- async get_listing_oauth_credentials_status(listing_id) {
2973
- const [data] = await this.request("GET", `/market/capabilities/${listing_id}/oauth-credentials`);
2974
- return { ...data };
2975
- }
2976
- // ----- end connected accounts --------------------------------------------
3004
+ // ----- Connected accounts ------------------------------------------------
3005
+ // Architecture B: publisher APIs own external OAuth and token storage.
3006
+ // The SDK no longer exposes platform OAuth or listing credential APIs.
2977
3007
  async get_developer_portal() {
2978
3008
  const [data, meta] = await this.request("GET", "/market/developer/portal");
2979
3009
  return {
@@ -3006,7 +3036,6 @@ var init_client = __esm({
3006
3036
  dry_run_supported: Boolean(data.dry_run_supported ?? false),
3007
3037
  approval_mode: stringOrNull(data.approval_mode),
3008
3038
  required_connected_accounts: Array.isArray(data.required_connected_accounts) ? data.required_connected_accounts : [],
3009
- connected_accounts: Array.isArray(data.connected_accounts) ? data.connected_accounts.filter((item) => isRecord(item)).map((item) => ({ ...item })) : [],
3010
3039
  stub_providers_enabled: Boolean(data.stub_providers_enabled ?? false),
3011
3040
  simulated_receipts: Boolean(data.simulated_receipts ?? false),
3012
3041
  approval_simulator: Boolean(data.approval_simulator ?? false),
@@ -4304,25 +4333,6 @@ var init_client = __esm({
4304
4333
  raw: { ...data }
4305
4334
  };
4306
4335
  }
4307
- async list_connected_accounts(options = {}) {
4308
- const params = {
4309
- provider_key: options.provider_key,
4310
- environment: options.environment,
4311
- limit: Math.max(1, Math.min(Math.trunc(options.limit ?? 50), 100)),
4312
- cursor: options.cursor
4313
- };
4314
- const [data, meta] = await this.request("GET", "/market/connected-accounts", { params });
4315
- const items = Array.isArray(data.items) ? data.items.filter((item) => isRecord(item)).map(parseConnectedAccount) : [];
4316
- const next_cursor = stringOrNull(data.next_cursor);
4317
- return new CursorPageResult({
4318
- items,
4319
- next_cursor,
4320
- limit: typeof data.limit === "number" ? data.limit : params.limit,
4321
- offset: typeof data.offset === "number" ? data.offset : null,
4322
- meta,
4323
- fetchNext: next_cursor ? (cursor) => this.list_connected_accounts({ ...options, cursor }) : void 0
4324
- });
4325
- }
4326
4336
  async create_support_case(subject, body, options = {}) {
4327
4337
  const summary = subject.trim();
4328
4338
  const details = body.trim();
@@ -5417,53 +5427,8 @@ function stableValue(value) {
5417
5427
  return value;
5418
5428
  }
5419
5429
 
5420
- // src/types.ts
5421
- var PermissionClass = {
5422
- READ_ONLY: "read-only",
5423
- ACTION: "action",
5424
- PAYMENT: "payment",
5425
- /** @deprecated Use READ_ONLY. Behaves identically. */
5426
- RECOMMENDATION: "recommendation"
5427
- };
5428
- var ApprovalMode = {
5429
- AUTO: "auto",
5430
- BUDGET_BOUNDED: "budget-bounded",
5431
- ALWAYS_ASK: "always-ask",
5432
- DENY: "deny"
5433
- };
5434
- var Environment = {
5435
- SANDBOX: "sandbox",
5436
- LIVE: "live"
5437
- };
5438
- var PriceModel = {
5439
- FREE: "free",
5440
- SUBSCRIPTION: "subscription",
5441
- ONE_TIME: "one_time",
5442
- BUNDLE: "bundle",
5443
- USAGE_BASED: "usage_based",
5444
- PER_ACTION: "per_action"
5445
- };
5446
- var AppCategory = {
5447
- COMMERCE: "commerce",
5448
- BOOKING: "booking",
5449
- CRM: "crm",
5450
- FINANCE: "finance",
5451
- DOCUMENT: "document",
5452
- COMMUNICATION: "communication",
5453
- MONITORING: "monitoring",
5454
- OTHER: "other"
5455
- };
5456
- var ToolManualPermissionClass = {
5457
- READ_ONLY: "read_only",
5458
- ACTION: "action",
5459
- PAYMENT: "payment"
5460
- };
5461
- var SettlementMode = {
5462
- STRIPE_CHECKOUT: "stripe_checkout",
5463
- STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
5464
- POLYGON_MANDATE: "polygon_mandate",
5465
- EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
5466
- };
5430
+ // src/runtime.ts
5431
+ init_types();
5467
5432
 
5468
5433
  // src/testing/recorder.ts
5469
5434
  var CASSETTE_VERSION = 1;
@@ -5855,6 +5820,7 @@ Actual: ${requestSignature(requestRecord, ignoreBodyFields)}`
5855
5820
  };
5856
5821
 
5857
5822
  // src/tool-manual-validator.ts
5823
+ init_types();
5858
5824
  init_utils();
5859
5825
  var JURISDICTION_PATTERN = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/;
5860
5826
  var TOOL_NAME_RE = /^[A-Za-z0-9_]{3,64}$/;
@@ -6126,6 +6092,64 @@ function validate_tool_manual(manualInput) {
6126
6092
  // src/runtime.ts
6127
6093
  init_web3();
6128
6094
  var CAPABILITY_KEY_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
6095
+ var MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2 = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
6096
+ function pricingPlanFloorIssues(plan, defaultCurrency) {
6097
+ const issues = [];
6098
+ if (plan === void 0 || plan === null) {
6099
+ return issues;
6100
+ }
6101
+ if (typeof plan !== "object" || Array.isArray(plan)) {
6102
+ return ["pricing_plan must be an object when provided"];
6103
+ }
6104
+ const record = plan;
6105
+ const items = record.items;
6106
+ if (items === void 0 || items === null) {
6107
+ return issues;
6108
+ }
6109
+ if (!Array.isArray(items)) {
6110
+ return ["pricing_plan.items must be an array when provided"];
6111
+ }
6112
+ const planCurrency = String(record.currency ?? defaultCurrency ?? "").trim().toUpperCase();
6113
+ const seenKeys = /* @__PURE__ */ new Set();
6114
+ items.forEach((item, index) => {
6115
+ if (typeof item !== "object" || item === null || Array.isArray(item)) {
6116
+ issues.push(`pricing_plan.items[${index}] must be an object`);
6117
+ return;
6118
+ }
6119
+ const itemRecord = item;
6120
+ const itemKey = String(
6121
+ itemRecord.key ?? itemRecord.operation ?? itemRecord.operation_key ?? itemRecord.request_type ?? itemRecord.receipt_code ?? itemRecord.action ?? ""
6122
+ ).trim();
6123
+ if (!itemKey) {
6124
+ issues.push(`pricing_plan.items[${index}].key is required`);
6125
+ } else if (seenKeys.has(itemKey)) {
6126
+ issues.push(`pricing_plan.items[${index}].key duplicates ${itemKey}`);
6127
+ } else {
6128
+ seenKeys.add(itemKey);
6129
+ }
6130
+ const amountRaw = itemRecord.price_minor ?? itemRecord.amount_minor ?? itemRecord.cost_minor ?? itemRecord.value_minor;
6131
+ if (amountRaw === void 0 || amountRaw === null) {
6132
+ issues.push(`pricing_plan.items[${index}].price_minor is required`);
6133
+ return;
6134
+ }
6135
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
6136
+ if (!Number.isInteger(amountMinor)) {
6137
+ issues.push(`pricing_plan.items[${index}].price_minor must be an integer`);
6138
+ return;
6139
+ }
6140
+ if (amountMinor < 0) {
6141
+ issues.push(`pricing_plan.items[${index}].price_minor must be zero or positive`);
6142
+ return;
6143
+ }
6144
+ const currency = String(itemRecord.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
6145
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
6146
+ issues.push(
6147
+ `pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing`
6148
+ );
6149
+ }
6150
+ });
6151
+ return issues;
6152
+ }
6129
6153
  function normalizeExecutionResult(result, executionKind) {
6130
6154
  return {
6131
6155
  success: Boolean(result.success),
@@ -6166,24 +6190,12 @@ var AppTestHarness = class {
6166
6190
  this.stubs = stubs;
6167
6191
  }
6168
6192
  async executeWithKind(execution_kind, task_type = "default", options = {}) {
6169
- const connected_accounts = options.connected_accounts ?? Object.fromEntries(
6170
- Object.keys(this.stubs).map((key) => [
6171
- key,
6172
- {
6173
- provider_key: key,
6174
- session_token: `stub-token-${key}`,
6175
- environment: Environment.SANDBOX,
6176
- scopes: []
6177
- }
6178
- ])
6179
- );
6180
6193
  const ctx = {
6181
6194
  agent_id: "test-agent-001",
6182
6195
  owner_user_id: "test-owner-001",
6183
6196
  task_type,
6184
6197
  environment: Environment.SANDBOX,
6185
6198
  execution_kind,
6186
- connected_accounts,
6187
6199
  input_params: options.input_params ?? {},
6188
6200
  trace_id: options.trace_id,
6189
6201
  idempotency_key: options.idempotency_key,
@@ -6225,6 +6237,10 @@ var AppTestHarness = class {
6225
6237
  if (!manifest.example_prompts || manifest.example_prompts.length === 0) {
6226
6238
  issues.push("at least one example_prompt is recommended");
6227
6239
  }
6240
+ issues.push(...pricingPlanFloorIssues(manifest.pricing_plan, String(manifest.currency ?? "USD")));
6241
+ if ((manifest.price_model === PriceModel.USAGE_BASED || manifest.price_model === PriceModel.PER_ACTION) && (!manifest.pricing_plan || !Array.isArray(manifest.pricing_plan.items) || manifest.pricing_plan.items.length === 0)) {
6242
+ issues.push("pricing_plan.items is required for usage_based/per_action pricing");
6243
+ }
6228
6244
  if (manifest.permission_class === PermissionClass.ACTION || manifest.permission_class === PermissionClass.PAYMENT) {
6229
6245
  if (!manifest.dry_run_supported) {
6230
6246
  issues.push("action/payment apps should support dry_run");
@@ -6273,12 +6289,6 @@ var AppTestHarness = class {
6273
6289
  }
6274
6290
  return issues;
6275
6291
  }
6276
- async simulate_connected_account_missing(task_type = "default", options = {}) {
6277
- return this.executeWithKind("dry_run", task_type, {
6278
- ...options,
6279
- connected_accounts: {}
6280
- });
6281
- }
6282
6292
  async simulate_metering(record, options = {}) {
6283
6293
  const { normalizeUsageRecord: normalizeUsageRecord2 } = await Promise.resolve().then(() => (init_metering(), metering_exports));
6284
6294
  const manifest = await this.app.manifest();
@@ -6306,7 +6316,7 @@ var AppTestHarness = class {
6306
6316
  };
6307
6317
  }
6308
6318
  return {
6309
- experimental: manifest.price_model === PriceModel.USAGE_BASED || manifest.price_model === PriceModel.PER_ACTION,
6319
+ experimental: false,
6310
6320
  usage_record,
6311
6321
  invoice_line_preview
6312
6322
  };
@@ -7241,15 +7251,6 @@ async function loadProject(path = ".") {
7241
7251
  const tool_manual = tool_manual_path ? JSON.parse(await (0, import_promises.readFile)(tool_manual_path, "utf8")) : buildToolManualTemplate(manifest);
7242
7252
  const runtime_validation_path = await findRuntimeValidationPath(root_dir);
7243
7253
  const runtime_validation = runtime_validation_path ? await loadJsonObject(runtime_validation_path, "runtime_validation") : void 0;
7244
- const oauth_credentials_path = await findOauthCredentialsPath(root_dir);
7245
- let oauth_credentials;
7246
- if (oauth_credentials_path) {
7247
- const parsed = JSON.parse(await (0, import_promises.readFile)(oauth_credentials_path, "utf8"));
7248
- if (!isRecord(parsed) && !Array.isArray(parsed)) {
7249
- throw new SiglumeProjectError("oauth_credentials must be a JSON object or array");
7250
- }
7251
- oauth_credentials = parsed;
7252
- }
7253
7254
  return {
7254
7255
  root_dir,
7255
7256
  adapter_path,
@@ -7258,9 +7259,7 @@ async function loadProject(path = ".") {
7258
7259
  tool_manual_path: tool_manual_path ?? void 0,
7259
7260
  tool_manual,
7260
7261
  runtime_validation_path: runtime_validation_path ?? void 0,
7261
- runtime_validation,
7262
- oauth_credentials_path: oauth_credentials_path ?? void 0,
7263
- oauth_credentials
7262
+ runtime_validation
7264
7263
  };
7265
7264
  }
7266
7265
  function isPlatformManagedRequirement(value) {
@@ -7298,6 +7297,21 @@ function requiredOauthProviders(requirements) {
7298
7297
  }
7299
7298
  return providers;
7300
7299
  }
7300
+ function apiManagedRequirementsMissingConnectUrl(requirements) {
7301
+ const missing = [];
7302
+ for (const item of requirements ?? []) {
7303
+ if (!isRecord(item)) continue;
7304
+ const managedBy = String(item.managed_by ?? "").trim().toLowerCase().replaceAll("_", "-");
7305
+ if (managedBy !== "api") continue;
7306
+ const connectUrl = String(item.connect_url ?? "").trim();
7307
+ if (connectUrl) continue;
7308
+ const label = oauthProviderKeyFromRequirement(item) ?? "(missing provider_key)";
7309
+ if (!missing.includes(label)) {
7310
+ missing.push(label);
7311
+ }
7312
+ }
7313
+ return missing;
7314
+ }
7301
7315
  function connectedAccountRequirementLabel(value) {
7302
7316
  if (isRecord(value)) {
7303
7317
  for (const key of ["provider_key", "provider", "account_type", "name"]) {
@@ -7308,102 +7322,6 @@ function connectedAccountRequirementLabel(value) {
7308
7322
  }
7309
7323
  return String(value ?? "").trim();
7310
7324
  }
7311
- function oauthProviderRecordsMap(payload) {
7312
- if (!payload) {
7313
- return {};
7314
- }
7315
- const items = Array.isArray(payload) ? payload : Array.isArray(payload.items) ? payload.items : [payload];
7316
- const resolved = {};
7317
- for (const [index, item] of items.entries()) {
7318
- if (!isRecord(item)) {
7319
- throw new SiglumeProjectError(`oauth_credentials[${index}] must be a JSON object.`);
7320
- }
7321
- const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
7322
- if (!providerKey) {
7323
- throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is required.`);
7324
- }
7325
- const authorizeUrl = String(item.authorize_url ?? item.authorization_url ?? item.auth_url ?? "").trim();
7326
- const tokenUrl = String(item.token_url ?? "").trim();
7327
- if (!authorizeUrl || !tokenUrl) {
7328
- throw new SiglumeProjectError(
7329
- `oauth_credentials[${index}] must include authorize_url and token_url.`
7330
- );
7331
- }
7332
- for (const [urlKey, urlValue] of Object.entries({
7333
- authorize_url: authorizeUrl,
7334
- token_url: tokenUrl,
7335
- revoke_url: String(item.revoke_url ?? "").trim()
7336
- })) {
7337
- if (urlValue && !urlValue.startsWith("https://")) {
7338
- throw new SiglumeProjectError(`oauth_credentials[${index}].${urlKey} must be an https URL.`);
7339
- }
7340
- }
7341
- const clientId = String(item.client_id ?? "").trim();
7342
- const clientSecret = String(item.client_secret ?? "").trim();
7343
- if (!clientId || !clientSecret) {
7344
- throw new SiglumeProjectError(`oauth_credentials[${index}] must include client_id and client_secret.`);
7345
- }
7346
- const rawScopes = item.required_scopes ?? item.scopes;
7347
- let scopes = [];
7348
- if (rawScopes == null) {
7349
- scopes = [];
7350
- } else if (!Array.isArray(rawScopes)) {
7351
- throw new SiglumeProjectError(`oauth_credentials[${index}].required_scopes must be a JSON array.`);
7352
- } else {
7353
- scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7354
- }
7355
- const record = {
7356
- provider_key: providerKey,
7357
- client_id: clientId,
7358
- client_secret: clientSecret,
7359
- required_scopes: scopes
7360
- };
7361
- for (const [key, value] of Object.entries({
7362
- authorize_url: authorizeUrl,
7363
- token_url: tokenUrl,
7364
- revoke_url: String(item.revoke_url ?? "").trim(),
7365
- display_name: String(item.display_name ?? "").trim(),
7366
- scope_separator: String(item.scope_separator ?? "").trim(),
7367
- token_endpoint_auth: String(item.token_endpoint_auth ?? "").trim()
7368
- })) {
7369
- if (value) record[key] = value;
7370
- }
7371
- for (const key of ["pkce_required", "refresh_supported"]) {
7372
- if (typeof item[key] === "boolean") record[key] = item[key];
7373
- }
7374
- if (Array.isArray(item.available_scopes)) {
7375
- const availableScopes = item.available_scopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7376
- if (availableScopes.length > 0) record.available_scopes = availableScopes;
7377
- }
7378
- resolved[providerKey] = record;
7379
- }
7380
- return resolved;
7381
- }
7382
- function canonicalOauthCredentialsPayload(payload) {
7383
- const records = oauthProviderRecordsMap(payload);
7384
- const providerKeys = Object.keys(records).sort();
7385
- if (providerKeys.length === 0) {
7386
- return void 0;
7387
- }
7388
- return {
7389
- items: providerKeys.map((providerKey) => records[providerKey])
7390
- };
7391
- }
7392
- function ensureRequiredOauthCredentials(project) {
7393
- const requiredProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
7394
- if (requiredProviders.length === 0) {
7395
- return;
7396
- }
7397
- const provided = new Set(Object.keys(oauthProviderRecordsMap(project.oauth_credentials)));
7398
- const missing = requiredProviders.filter((provider) => !provided.has(provider));
7399
- if (missing.length === 0) {
7400
- return;
7401
- }
7402
- const path = project.oauth_credentials_path ?? (0, import_node_path.join)(project.root_dir, "oauth_credentials.json");
7403
- throw new SiglumeProjectError(
7404
- `${path} is required for platform-managed OAuth APIs. Missing provider seeds: ${missing.join(", ")}`
7405
- );
7406
- }
7407
7325
  async function validateProject(path = ".", deps = {}) {
7408
7326
  const project = await loadProject(path);
7409
7327
  const manifest_issues = await projectValidationIssues(project);
@@ -7558,10 +7476,21 @@ function ensureExplicitToolManual(project) {
7558
7476
  async function registrationPreflight(project, client) {
7559
7477
  const manifestIssues = await projectValidationIssues(project);
7560
7478
  const [toolManualValid, toolManualIssues] = validate_tool_manual(project.tool_manual);
7479
+ const retiredPlatformOauthProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
7480
+ if (retiredPlatformOauthProviders.length > 0) {
7481
+ throw new SiglumeProjectError(
7482
+ `Registration preflight failed. Fix these before calling auto-register:
7483
+ - platform-managed OAuth is retired. Use managed_by="api" with connect_url: ${retiredPlatformOauthProviders.join(", ")}`
7484
+ );
7485
+ }
7486
+ const apiManagedMissingConnectUrl = apiManagedRequirementsMissingConnectUrl(project.manifest.required_connected_accounts ?? []);
7487
+ if (apiManagedMissingConnectUrl.length > 0) {
7488
+ throw new SiglumeProjectError(
7489
+ `Registration preflight failed. Fix these before calling auto-register:
7490
+ - API-managed OAuth requirements must include connect_url: ${apiManagedMissingConnectUrl.join(", ")}`
7491
+ );
7492
+ }
7561
7493
  const remoteQuality = await client.preview_quality_score(project.tool_manual);
7562
- const requiredOauthProvidersList = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
7563
- const oauthProviderRecords = oauthProviderRecordsMap(project.oauth_credentials);
7564
- const missingOauthProviders = requiredOauthProvidersList.filter((provider) => !oauthProviderRecords[provider]);
7565
7494
  const blockingToolManualIssues = toolManualIssues.filter((issue2) => issue2.severity === "error");
7566
7495
  const errors = [
7567
7496
  ...manifestIssues.map((issue2) => String(issue2)),
@@ -7573,17 +7502,12 @@ async function registrationPreflight(project, client) {
7573
7502
  if (!remoteQualityOk(remoteQuality)) {
7574
7503
  errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
7575
7504
  }
7576
- if (missingOauthProviders.length > 0) {
7577
- errors.push(`oauth_credentials.json is required for platform-managed OAuth APIs: ${missingOauthProviders.join(", ")}`);
7578
- }
7579
7505
  const preflight = {
7580
7506
  manifest_issues: manifestIssues,
7581
7507
  tool_manual_valid: toolManualValid,
7582
7508
  tool_manual_issues: toolManualIssues.map((issue2) => toJsonable(issue2)),
7583
7509
  remote_quality: toJsonable(remoteQuality),
7584
- required_oauth_providers: requiredOauthProvidersList,
7585
- oauth_credentials_path: project.oauth_credentials_path ?? null,
7586
- oauth_missing_providers: missingOauthProviders,
7510
+ retired_platform_oauth_providers: retiredPlatformOauthProviders,
7587
7511
  ok: errors.length === 0
7588
7512
  };
7589
7513
  if (errors.length > 0) {
@@ -7622,8 +7546,6 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7622
7546
  ensureExplicitToolManual(project);
7623
7547
  ensureManifestPublisherIdentity(project);
7624
7548
  ensureRuntimeValidationReady(project);
7625
- ensureRequiredOauthCredentials(project);
7626
- const canonicalOauthCredentials = canonicalOauthCredentialsPayload(project.oauth_credentials);
7627
7549
  const client = await createClient(deps);
7628
7550
  if (requestedCompanySlug) {
7629
7551
  const slug = companyNameSlug(requestedCompanySlug);
@@ -7700,14 +7622,12 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7700
7622
  }
7701
7623
  }
7702
7624
  const receipt = await client.auto_register(project.manifest, project.tool_manual, {
7703
- runtime_validation: project.runtime_validation,
7704
- oauth_credentials: canonicalOauthCredentials
7625
+ runtime_validation: project.runtime_validation
7705
7626
  });
7706
7627
  const result = {
7707
7628
  receipt: toJsonable(receipt),
7708
7629
  registration_preflight: preflight,
7709
- runtime_validation_path: project.runtime_validation_path ?? null,
7710
- oauth_credentials_path: project.oauth_credentials_path ?? null
7630
+ runtime_validation_path: project.runtime_validation_path ?? null
7711
7631
  };
7712
7632
  if (developerPortalPreflight) {
7713
7633
  result.developer_portal_preflight = developerPortalPreflight;
@@ -7728,7 +7648,6 @@ async function runPreflight(path = ".", deps = {}) {
7728
7648
  ensureExplicitToolManual(project);
7729
7649
  ensureManifestPublisherIdentity(project);
7730
7650
  ensureRuntimeValidationReady(project);
7731
- ensureRequiredOauthCredentials(project);
7732
7651
  const client = await createClient(deps);
7733
7652
  const preflight = await registrationPreflight(project, client);
7734
7653
  let developerPortalPreflight = null;
@@ -7746,8 +7665,7 @@ async function runPreflight(path = ".", deps = {}) {
7746
7665
  ok: true,
7747
7666
  adapter_path: project.adapter_path,
7748
7667
  registration_preflight: preflight,
7749
- runtime_validation_path: project.runtime_validation_path ?? null,
7750
- oauth_credentials_path: project.oauth_credentials_path ?? null
7668
+ runtime_validation_path: project.runtime_validation_path ?? null
7751
7669
  };
7752
7670
  if (developerPortalPreflight) {
7753
7671
  result.developer_portal_preflight = developerPortalPreflight;
@@ -8229,7 +8147,7 @@ function operationReadmeTemplate(operation, manifest, warning) {
8229
8147
  "- `tool_manual.json`: machine-generated ToolManual scaffold",
8230
8148
  "- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
8231
8149
  "- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
8232
- "- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
8150
+ "- `.gitignore`: keeps runtime review keys out of Git",
8233
8151
  "- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
8234
8152
  "",
8235
8153
  "Before registering, replace all generated placeholders:",
@@ -8237,8 +8155,8 @@ function operationReadmeTemplate(operation, manifest, warning) {
8237
8155
  "- Replace `support_contact` with a real support email address or public support URL.",
8238
8156
  "- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
8239
8157
  "- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
8240
- "- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
8241
- "- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
8158
+ "- If the API uses external OAuth, implement that flow in your API runtime and keep user tokens outside Siglume.",
8159
+ "- Do not commit real review keys or external-provider secrets; the generated `.gitignore` excludes local secret files.",
8242
8160
  "- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
8243
8161
  "",
8244
8162
  "## Commands",
@@ -8314,8 +8232,6 @@ function generatedGitignore() {
8314
8232
  "!.env.example",
8315
8233
  "runtime_validation.json",
8316
8234
  "runtime-validation.json",
8317
- "oauth_credentials.json",
8318
- "oauth-credentials.json",
8319
8235
  "",
8320
8236
  "# Python / test artifacts.",
8321
8237
  "__pycache__/",
@@ -8461,13 +8377,6 @@ async function runHarnessForProject(project) {
8461
8377
  checks.push(executionCheck("quote", await harness.execute_quote(task_type, { input_params: sample_input }), harness));
8462
8378
  checks.push(executionCheck("payment", await harness.execute_payment(task_type, { input_params: sample_input }), harness));
8463
8379
  }
8464
- checks.push(
8465
- executionCheck(
8466
- "missing_account_simulation",
8467
- await harness.simulate_connected_account_missing(task_type, { input_params: sample_input }),
8468
- harness
8469
- )
8470
- );
8471
8380
  return {
8472
8381
  adapter_path: project.adapter_path,
8473
8382
  task_type,
@@ -8570,15 +8479,6 @@ async function findRuntimeValidationPath(root_dir) {
8570
8479
  }
8571
8480
  return null;
8572
8481
  }
8573
- async function findOauthCredentialsPath(root_dir) {
8574
- for (const name of ["oauth_credentials.json", "oauth-credentials.json"]) {
8575
- const candidate = (0, import_node_path.join)(root_dir, name);
8576
- if ((0, import_node_fs.existsSync)(candidate)) {
8577
- return candidate;
8578
- }
8579
- }
8580
- return null;
8581
- }
8582
8482
  async function loadJsonObject(path, label) {
8583
8483
  let payload;
8584
8484
  try {
@@ -8810,15 +8710,15 @@ function readmeTemplate(template) {
8810
8710
  "- `tool_manual.json`: editable ToolManual draft for validation and registration",
8811
8711
  "- `runtime_validation.json`: local live API smoke-test contract used during registration",
8812
8712
  "- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
8813
- "- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
8713
+ "- `.gitignore`: keeps runtime review keys out of Git",
8814
8714
  "",
8815
8715
  "Before registering, replace all generated placeholders:",
8816
8716
  "- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
8817
8717
  "- Replace `support_contact` with a real support email address or public support URL.",
8818
8718
  "- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
8819
8719
  "- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
8820
- "- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
8821
- "- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
8720
+ "- If the API uses external OAuth, implement that flow in your API runtime and keep user tokens outside Siglume.",
8721
+ "- Do not commit real review keys or external-provider secrets; the generated `.gitignore` excludes local secret files.",
8822
8722
  "- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
8823
8723
  "",
8824
8724
  "Suggested workflow:",
@@ -9036,7 +8936,6 @@ async function runCli(argv, deps = {}) {
9036
8936
  emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
9037
8937
  }
9038
8938
  if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
9039
- if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
9040
8939
  });
9041
8940
  program.command("companies").description("List Siglume companies available for company-name publishing.").option("--json", "emit machine-readable JSON", false).action(async (options) => {
9042
8941
  const report = await listCompanyPublishersReport(deps);
@@ -9087,7 +8986,6 @@ async function runCli(argv, deps = {}) {
9087
8986
  emit(stdout, `listing_id: ${receipt.listing_id}`);
9088
8987
  emit(stdout, `receipt_status: ${receipt.status}`);
9089
8988
  if (receipt.listing_status) emit(stdout, `listing_status: ${receipt.listing_status}`);
9090
- if (receipt.oauth_status) emit(stdout, `oauth_configured: ${Boolean(receipt.oauth_status.configured)}`);
9091
8989
  if (receipt.review_url) emit(stdout, `review_url: ${receipt.review_url}`);
9092
8990
  if (receipt.trace_id) emit(stdout, `trace_id: ${receipt.trace_id}`);
9093
8991
  if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);