@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.
@@ -177,6 +177,61 @@ var init_utils = __esm({
177
177
  }
178
178
  });
179
179
 
180
+ // src/types.ts
181
+ var PermissionClass, ApprovalMode, Environment, PriceModel, AppCategory, MINIMUM_JPY_OPERATION_PRICE_MINOR, ToolManualPermissionClass, SettlementMode;
182
+ var init_types = __esm({
183
+ "src/types.ts"() {
184
+ "use strict";
185
+ PermissionClass = {
186
+ READ_ONLY: "read-only",
187
+ ACTION: "action",
188
+ PAYMENT: "payment",
189
+ /** @deprecated Use READ_ONLY. Behaves identically. */
190
+ RECOMMENDATION: "recommendation"
191
+ };
192
+ ApprovalMode = {
193
+ AUTO: "auto",
194
+ BUDGET_BOUNDED: "budget-bounded",
195
+ ALWAYS_ASK: "always-ask",
196
+ DENY: "deny"
197
+ };
198
+ Environment = {
199
+ SANDBOX: "sandbox",
200
+ LIVE: "live"
201
+ };
202
+ PriceModel = {
203
+ FREE: "free",
204
+ SUBSCRIPTION: "subscription",
205
+ ONE_TIME: "one_time",
206
+ BUNDLE: "bundle",
207
+ USAGE_BASED: "usage_based",
208
+ PER_ACTION: "per_action"
209
+ };
210
+ AppCategory = {
211
+ COMMERCE: "commerce",
212
+ BOOKING: "booking",
213
+ CRM: "crm",
214
+ FINANCE: "finance",
215
+ DOCUMENT: "document",
216
+ COMMUNICATION: "communication",
217
+ MONITORING: "monitoring",
218
+ OTHER: "other"
219
+ };
220
+ MINIMUM_JPY_OPERATION_PRICE_MINOR = 15;
221
+ ToolManualPermissionClass = {
222
+ READ_ONLY: "read_only",
223
+ ACTION: "action",
224
+ PAYMENT: "payment"
225
+ };
226
+ SettlementMode = {
227
+ STRIPE_CHECKOUT: "stripe_checkout",
228
+ STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
229
+ POLYGON_MANDATE: "polygon_mandate",
230
+ EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
231
+ };
232
+ }
233
+ });
234
+
180
235
  // src/webhooks.ts
181
236
  function isRecord2(value) {
182
237
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1298,6 +1353,58 @@ function validateSaveDataSchema(schema, fieldName) {
1298
1353
  }
1299
1354
  }
1300
1355
  }
1356
+ function validatePricingPlanFloor(plan, defaultCurrency) {
1357
+ if (plan === void 0 || plan === null) {
1358
+ return;
1359
+ }
1360
+ if (!isRecord(plan)) {
1361
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
1362
+ }
1363
+ const items = plan.items;
1364
+ if (items === void 0 || items === null) {
1365
+ return;
1366
+ }
1367
+ if (!Array.isArray(items)) {
1368
+ throw new SiglumeClientError("AppManifest.pricing_plan.items must be an array when provided.");
1369
+ }
1370
+ const planCurrency = String(plan.currency ?? defaultCurrency ?? "").trim().toUpperCase();
1371
+ const seenKeys = /* @__PURE__ */ new Set();
1372
+ items.forEach((item, index) => {
1373
+ if (!isRecord(item)) {
1374
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}] must be an object.`);
1375
+ }
1376
+ const itemKey = String(
1377
+ item.key ?? item.operation ?? item.operation_key ?? item.request_type ?? item.receipt_code ?? item.action ?? ""
1378
+ ).trim();
1379
+ if (!itemKey) {
1380
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key is required.`);
1381
+ }
1382
+ if (seenKeys.has(itemKey)) {
1383
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key duplicates ${itemKey}.`);
1384
+ }
1385
+ seenKeys.add(itemKey);
1386
+ const amountRaw = item.price_minor ?? item.amount_minor ?? item.cost_minor ?? item.value_minor;
1387
+ if (amountRaw === void 0 || amountRaw === null) {
1388
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor is required.`);
1389
+ }
1390
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
1391
+ if (!Number.isInteger(amountMinor)) {
1392
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be an integer.`);
1393
+ }
1394
+ if (amountMinor < 0) {
1395
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be zero or positive.`);
1396
+ }
1397
+ const currency = String(item.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
1398
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
1399
+ throw new SiglumeClientError(
1400
+ `AppManifest.pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing.`
1401
+ );
1402
+ }
1403
+ });
1404
+ }
1405
+ function pricingPlanHasItems(plan) {
1406
+ return isRecord(plan) && Array.isArray(plan.items) && plan.items.length > 0;
1407
+ }
1301
1408
  function buildToolManualQualityReport(payload) {
1302
1409
  const qualityBlock = isRecord(payload.quality) ? payload.quality : payload;
1303
1410
  const issues = [];
@@ -1373,6 +1480,7 @@ function buildUrl(baseUrl, path, params) {
1373
1480
  }
1374
1481
  function parseListing(data) {
1375
1482
  const metadata = isRecord(data.metadata) ? data.metadata : {};
1483
+ const pricing_plan = isRecord(data.pricing_plan) ? data.pricing_plan : isRecord(metadata.pricing_plan) ? metadata.pricing_plan : null;
1376
1484
  const persistence = isRecord(data.persistence) ? data.persistence : isRecord(metadata.persistence) ? metadata.persistence : {};
1377
1485
  return {
1378
1486
  listing_id: String(data.listing_id ?? data.id ?? ""),
@@ -1386,6 +1494,7 @@ function parseListing(data) {
1386
1494
  dry_run_supported: Boolean(data.dry_run_supported ?? false),
1387
1495
  price_model: stringOrNull(data.price_model),
1388
1496
  price_value_minor: Number(data.price_value_minor ?? 0),
1497
+ pricing_plan,
1389
1498
  currency: String(data.currency ?? "USD"),
1390
1499
  allow_free_trial: Boolean(data.allow_free_trial ?? false),
1391
1500
  free_trial_duration_days: Number(data.free_trial_duration_days ?? 30),
@@ -1460,18 +1569,6 @@ function parseBundleMember(data) {
1460
1569
  link_id: stringOrNull(data.link_id)
1461
1570
  };
1462
1571
  }
1463
- function parseConnectedAccountLifecycle(data) {
1464
- return {
1465
- connected_account_id: String(data.connected_account_id ?? ""),
1466
- provider_key: String(data.provider_key ?? ""),
1467
- expires_at: stringOrNull(data.expires_at),
1468
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((s) => typeof s === "string") : [],
1469
- refreshed_at: stringOrNull(data.refreshed_at),
1470
- connection_status: stringOrNull(data.connection_status),
1471
- provider_revoked: typeof data.provider_revoked === "boolean" ? data.provider_revoked : null,
1472
- revoked_at: stringOrNull(data.revoked_at)
1473
- };
1474
- }
1475
1572
  function parseBundle(data) {
1476
1573
  const membersRaw = Array.isArray(data.members) ? data.members : [];
1477
1574
  return {
@@ -1550,21 +1647,6 @@ function parseBinding(data) {
1550
1647
  raw: { ...data }
1551
1648
  };
1552
1649
  }
1553
- function parseConnectedAccount(data) {
1554
- return {
1555
- connected_account_id: String(data.connected_account_id ?? data.id ?? ""),
1556
- provider_key: String(data.provider_key ?? ""),
1557
- account_role: String(data.account_role ?? ""),
1558
- display_name: stringOrNull(data.display_name),
1559
- environment: stringOrNull(data.environment),
1560
- connection_status: stringOrNull(data.connection_status),
1561
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((item) => typeof item === "string") : [],
1562
- metadata: toRecord(data.metadata),
1563
- created_at: stringOrNull(data.created_at),
1564
- updated_at: stringOrNull(data.updated_at),
1565
- raw: { ...data }
1566
- };
1567
- }
1568
1650
  function parseSupportCase(data) {
1569
1651
  return {
1570
1652
  support_case_id: String(data.support_case_id ?? data.id ?? ""),
@@ -2510,10 +2592,11 @@ function cloneJsonLike(value) {
2510
2592
  }
2511
2593
  return value;
2512
2594
  }
2513
- var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, CursorPageResult, SiglumeClient;
2595
+ var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, MINIMUM_JPY_OPERATION_PRICE_CURRENCIES, CursorPageResult, SiglumeClient;
2514
2596
  var init_client = __esm({
2515
2597
  "src/client.ts"() {
2516
2598
  "use strict";
2599
+ init_types();
2517
2600
  init_errors();
2518
2601
  init_webhooks();
2519
2602
  init_web3();
@@ -2521,6 +2604,7 @@ var init_client = __esm({
2521
2604
  init_utils();
2522
2605
  DEFAULT_SIGLUME_API_BASE = "https://siglume.com/v1";
2523
2606
  RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
2607
+ MINIMUM_JPY_OPERATION_PRICE_CURRENCIES = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
2524
2608
  CursorPageResult = class {
2525
2609
  items;
2526
2610
  next_cursor;
@@ -2603,13 +2687,6 @@ var init_client = __esm({
2603
2687
  if (options.runtime_validation) {
2604
2688
  payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
2605
2689
  }
2606
- if (options.oauth_credentials) {
2607
- payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
2608
- items: options.oauth_credentials.map(
2609
- (item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
2610
- )
2611
- } : coerceMapping(options.oauth_credentials, "oauth_credentials");
2612
- }
2613
2690
  if (options.source_context) {
2614
2691
  payload.source_context = coerceMapping(options.source_context, "source_context");
2615
2692
  }
@@ -2635,6 +2712,7 @@ var init_client = __esm({
2635
2712
  "jurisdiction",
2636
2713
  "price_model",
2637
2714
  "price_value_minor",
2715
+ "pricing_plan",
2638
2716
  "currency",
2639
2717
  "allow_free_trial",
2640
2718
  "free_trial_duration_days",
@@ -2651,6 +2729,9 @@ var init_client = __esm({
2651
2729
  payload[fieldName] = value;
2652
2730
  }
2653
2731
  }
2732
+ if (payload.pricing_plan !== void 0 && (typeof payload.pricing_plan !== "object" || Array.isArray(payload.pricing_plan))) {
2733
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
2734
+ }
2654
2735
  if (payload.store_vertical === void 0 || payload.store_vertical === null) {
2655
2736
  throw new SiglumeClientError(
2656
2737
  "AppManifest.store_vertical is required. Choose 'api' for normal API Store listings or 'game' for API games."
@@ -2666,6 +2747,13 @@ var init_client = __esm({
2666
2747
  throw new SiglumeClientError(`AppManifest.currency must be 'USD' or 'JPY'. Got ${String(payload.currency)}.`);
2667
2748
  }
2668
2749
  payload.currency = currency;
2750
+ if (payload.pricing_plan !== void 0) {
2751
+ validatePricingPlanFloor(payload.pricing_plan, currency);
2752
+ }
2753
+ const priceModel = String(payload.price_model ?? "free").trim().toLowerCase();
2754
+ if ((priceModel === "usage_based" || priceModel === "per_action") && !pricingPlanHasItems(payload.pricing_plan)) {
2755
+ throw new SiglumeClientError("AppManifest.pricing_plan.items is required for usage_based/per_action pricing.");
2756
+ }
2669
2757
  if (payload.allow_free_trial === void 0 || payload.allow_free_trial === null) {
2670
2758
  throw new SiglumeClientError(
2671
2759
  "AppManifest.allow_free_trial is required. Pass true to offer a Plus/Pro buyer free trial or false to disable trials."
@@ -2739,7 +2827,6 @@ var init_client = __esm({
2739
2827
  auto_manifest: toRecord(data.auto_manifest),
2740
2828
  confidence: toRecord(data.confidence),
2741
2829
  validation_report: toRecord(data.validation_report),
2742
- oauth_status: toRecord(data.oauth_status),
2743
2830
  review_url: stringOrNull(data.review_url),
2744
2831
  trace_id: meta.trace_id,
2745
2832
  request_id: meta.request_id
@@ -2915,66 +3002,9 @@ var init_client = __esm({
2915
3002
  return parseBundle(data);
2916
3003
  }
2917
3004
  // ----- end bundles -------------------------------------------------------
2918
- // ----- Connected accounts (v0.7 track 3) ---------------------------------
2919
- // `resolve()` is intentionally NOT wrapped: runtime-only, never over the wire.
2920
- async start_connected_account_oauth(input) {
2921
- const body = {
2922
- listing_id: input.listing_id,
2923
- redirect_uri: input.redirect_uri
2924
- };
2925
- if (input.scopes !== void 0) body.scopes = input.scopes;
2926
- if (input.account_role !== void 0) body.account_role = input.account_role;
2927
- const [data] = await this.request("POST", "/me/connected-accounts/oauth/authorize", {
2928
- json_body: body
2929
- });
2930
- return {
2931
- authorize_url: String(data.authorize_url ?? ""),
2932
- state: String(data.state ?? ""),
2933
- provider_key: String(data.provider_key ?? ""),
2934
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((s) => typeof s === "string") : [],
2935
- pkce_method: stringOrNull(data.pkce_method)
2936
- };
2937
- }
2938
- async complete_connected_account_oauth(input) {
2939
- const [data] = await this.request("POST", "/me/connected-accounts/oauth/callback", {
2940
- json_body: { state: input.state, code: input.code }
2941
- });
2942
- return { ...data };
2943
- }
2944
- async refresh_connected_account(account_id) {
2945
- const [data] = await this.request("POST", `/me/connected-accounts/${account_id}/refresh`);
2946
- return parseConnectedAccountLifecycle(data);
2947
- }
2948
- async revoke_connected_account(account_id) {
2949
- const [data] = await this.request("POST", `/me/connected-accounts/${account_id}/revoke`);
2950
- return parseConnectedAccountLifecycle(data);
2951
- }
2952
- async set_listing_oauth_credentials(listing_id, input) {
2953
- const body = {
2954
- provider_key: input.provider_key,
2955
- client_id: input.client_id,
2956
- client_secret: input.client_secret,
2957
- authorize_url: input.authorize_url,
2958
- token_url: input.token_url
2959
- };
2960
- if (input.revoke_url !== void 0) body.revoke_url = input.revoke_url;
2961
- if (input.display_name !== void 0) body.display_name = input.display_name;
2962
- if (input.scope_separator !== void 0) body.scope_separator = input.scope_separator;
2963
- if (input.token_endpoint_auth !== void 0) body.token_endpoint_auth = input.token_endpoint_auth;
2964
- if (input.pkce_required !== void 0) body.pkce_required = input.pkce_required;
2965
- if (input.refresh_supported !== void 0) body.refresh_supported = input.refresh_supported;
2966
- if (input.available_scopes !== void 0) body.available_scopes = input.available_scopes;
2967
- if (input.required_scopes !== void 0) body.required_scopes = input.required_scopes;
2968
- const [data] = await this.request("PUT", `/market/capabilities/${listing_id}/oauth-credentials`, {
2969
- json_body: body
2970
- });
2971
- return { ...data };
2972
- }
2973
- async get_listing_oauth_credentials_status(listing_id) {
2974
- const [data] = await this.request("GET", `/market/capabilities/${listing_id}/oauth-credentials`);
2975
- return { ...data };
2976
- }
2977
- // ----- end connected accounts --------------------------------------------
3005
+ // ----- Connected accounts ------------------------------------------------
3006
+ // Architecture B: publisher APIs own external OAuth and token storage.
3007
+ // The SDK no longer exposes platform OAuth or listing credential APIs.
2978
3008
  async get_developer_portal() {
2979
3009
  const [data, meta] = await this.request("GET", "/market/developer/portal");
2980
3010
  return {
@@ -3007,7 +3037,6 @@ var init_client = __esm({
3007
3037
  dry_run_supported: Boolean(data.dry_run_supported ?? false),
3008
3038
  approval_mode: stringOrNull(data.approval_mode),
3009
3039
  required_connected_accounts: Array.isArray(data.required_connected_accounts) ? data.required_connected_accounts : [],
3010
- connected_accounts: Array.isArray(data.connected_accounts) ? data.connected_accounts.filter((item) => isRecord(item)).map((item) => ({ ...item })) : [],
3011
3040
  stub_providers_enabled: Boolean(data.stub_providers_enabled ?? false),
3012
3041
  simulated_receipts: Boolean(data.simulated_receipts ?? false),
3013
3042
  approval_simulator: Boolean(data.approval_simulator ?? false),
@@ -4305,25 +4334,6 @@ var init_client = __esm({
4305
4334
  raw: { ...data }
4306
4335
  };
4307
4336
  }
4308
- async list_connected_accounts(options = {}) {
4309
- const params = {
4310
- provider_key: options.provider_key,
4311
- environment: options.environment,
4312
- limit: Math.max(1, Math.min(Math.trunc(options.limit ?? 50), 100)),
4313
- cursor: options.cursor
4314
- };
4315
- const [data, meta] = await this.request("GET", "/market/connected-accounts", { params });
4316
- const items = Array.isArray(data.items) ? data.items.filter((item) => isRecord(item)).map(parseConnectedAccount) : [];
4317
- const next_cursor = stringOrNull(data.next_cursor);
4318
- return new CursorPageResult({
4319
- items,
4320
- next_cursor,
4321
- limit: typeof data.limit === "number" ? data.limit : params.limit,
4322
- offset: typeof data.offset === "number" ? data.offset : null,
4323
- meta,
4324
- fetchNext: next_cursor ? (cursor) => this.list_connected_accounts({ ...options, cursor }) : void 0
4325
- });
4326
- }
4327
4337
  async create_support_case(subject, body, options = {}) {
4328
4338
  const summary = subject.trim();
4329
4339
  const details = body.trim();
@@ -5423,53 +5433,8 @@ function stableValue(value) {
5423
5433
  return value;
5424
5434
  }
5425
5435
 
5426
- // src/types.ts
5427
- var PermissionClass = {
5428
- READ_ONLY: "read-only",
5429
- ACTION: "action",
5430
- PAYMENT: "payment",
5431
- /** @deprecated Use READ_ONLY. Behaves identically. */
5432
- RECOMMENDATION: "recommendation"
5433
- };
5434
- var ApprovalMode = {
5435
- AUTO: "auto",
5436
- BUDGET_BOUNDED: "budget-bounded",
5437
- ALWAYS_ASK: "always-ask",
5438
- DENY: "deny"
5439
- };
5440
- var Environment = {
5441
- SANDBOX: "sandbox",
5442
- LIVE: "live"
5443
- };
5444
- var PriceModel = {
5445
- FREE: "free",
5446
- SUBSCRIPTION: "subscription",
5447
- ONE_TIME: "one_time",
5448
- BUNDLE: "bundle",
5449
- USAGE_BASED: "usage_based",
5450
- PER_ACTION: "per_action"
5451
- };
5452
- var AppCategory = {
5453
- COMMERCE: "commerce",
5454
- BOOKING: "booking",
5455
- CRM: "crm",
5456
- FINANCE: "finance",
5457
- DOCUMENT: "document",
5458
- COMMUNICATION: "communication",
5459
- MONITORING: "monitoring",
5460
- OTHER: "other"
5461
- };
5462
- var ToolManualPermissionClass = {
5463
- READ_ONLY: "read_only",
5464
- ACTION: "action",
5465
- PAYMENT: "payment"
5466
- };
5467
- var SettlementMode = {
5468
- STRIPE_CHECKOUT: "stripe_checkout",
5469
- STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
5470
- POLYGON_MANDATE: "polygon_mandate",
5471
- EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
5472
- };
5436
+ // src/runtime.ts
5437
+ init_types();
5473
5438
 
5474
5439
  // src/testing/recorder.ts
5475
5440
  var CASSETTE_VERSION = 1;
@@ -5861,6 +5826,7 @@ Actual: ${requestSignature(requestRecord, ignoreBodyFields)}`
5861
5826
  };
5862
5827
 
5863
5828
  // src/tool-manual-validator.ts
5829
+ init_types();
5864
5830
  init_utils();
5865
5831
  var JURISDICTION_PATTERN = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/;
5866
5832
  var TOOL_NAME_RE = /^[A-Za-z0-9_]{3,64}$/;
@@ -6132,6 +6098,64 @@ function validate_tool_manual(manualInput) {
6132
6098
  // src/runtime.ts
6133
6099
  init_web3();
6134
6100
  var CAPABILITY_KEY_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
6101
+ var MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2 = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
6102
+ function pricingPlanFloorIssues(plan, defaultCurrency) {
6103
+ const issues = [];
6104
+ if (plan === void 0 || plan === null) {
6105
+ return issues;
6106
+ }
6107
+ if (typeof plan !== "object" || Array.isArray(plan)) {
6108
+ return ["pricing_plan must be an object when provided"];
6109
+ }
6110
+ const record = plan;
6111
+ const items = record.items;
6112
+ if (items === void 0 || items === null) {
6113
+ return issues;
6114
+ }
6115
+ if (!Array.isArray(items)) {
6116
+ return ["pricing_plan.items must be an array when provided"];
6117
+ }
6118
+ const planCurrency = String(record.currency ?? defaultCurrency ?? "").trim().toUpperCase();
6119
+ const seenKeys = /* @__PURE__ */ new Set();
6120
+ items.forEach((item, index) => {
6121
+ if (typeof item !== "object" || item === null || Array.isArray(item)) {
6122
+ issues.push(`pricing_plan.items[${index}] must be an object`);
6123
+ return;
6124
+ }
6125
+ const itemRecord = item;
6126
+ const itemKey = String(
6127
+ itemRecord.key ?? itemRecord.operation ?? itemRecord.operation_key ?? itemRecord.request_type ?? itemRecord.receipt_code ?? itemRecord.action ?? ""
6128
+ ).trim();
6129
+ if (!itemKey) {
6130
+ issues.push(`pricing_plan.items[${index}].key is required`);
6131
+ } else if (seenKeys.has(itemKey)) {
6132
+ issues.push(`pricing_plan.items[${index}].key duplicates ${itemKey}`);
6133
+ } else {
6134
+ seenKeys.add(itemKey);
6135
+ }
6136
+ const amountRaw = itemRecord.price_minor ?? itemRecord.amount_minor ?? itemRecord.cost_minor ?? itemRecord.value_minor;
6137
+ if (amountRaw === void 0 || amountRaw === null) {
6138
+ issues.push(`pricing_plan.items[${index}].price_minor is required`);
6139
+ return;
6140
+ }
6141
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
6142
+ if (!Number.isInteger(amountMinor)) {
6143
+ issues.push(`pricing_plan.items[${index}].price_minor must be an integer`);
6144
+ return;
6145
+ }
6146
+ if (amountMinor < 0) {
6147
+ issues.push(`pricing_plan.items[${index}].price_minor must be zero or positive`);
6148
+ return;
6149
+ }
6150
+ const currency = String(itemRecord.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
6151
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
6152
+ issues.push(
6153
+ `pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing`
6154
+ );
6155
+ }
6156
+ });
6157
+ return issues;
6158
+ }
6135
6159
  function normalizeExecutionResult(result, executionKind) {
6136
6160
  return {
6137
6161
  success: Boolean(result.success),
@@ -6172,24 +6196,12 @@ var AppTestHarness = class {
6172
6196
  this.stubs = stubs;
6173
6197
  }
6174
6198
  async executeWithKind(execution_kind, task_type = "default", options = {}) {
6175
- const connected_accounts = options.connected_accounts ?? Object.fromEntries(
6176
- Object.keys(this.stubs).map((key) => [
6177
- key,
6178
- {
6179
- provider_key: key,
6180
- session_token: `stub-token-${key}`,
6181
- environment: Environment.SANDBOX,
6182
- scopes: []
6183
- }
6184
- ])
6185
- );
6186
6199
  const ctx = {
6187
6200
  agent_id: "test-agent-001",
6188
6201
  owner_user_id: "test-owner-001",
6189
6202
  task_type,
6190
6203
  environment: Environment.SANDBOX,
6191
6204
  execution_kind,
6192
- connected_accounts,
6193
6205
  input_params: options.input_params ?? {},
6194
6206
  trace_id: options.trace_id,
6195
6207
  idempotency_key: options.idempotency_key,
@@ -6231,6 +6243,10 @@ var AppTestHarness = class {
6231
6243
  if (!manifest.example_prompts || manifest.example_prompts.length === 0) {
6232
6244
  issues.push("at least one example_prompt is recommended");
6233
6245
  }
6246
+ issues.push(...pricingPlanFloorIssues(manifest.pricing_plan, String(manifest.currency ?? "USD")));
6247
+ 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)) {
6248
+ issues.push("pricing_plan.items is required for usage_based/per_action pricing");
6249
+ }
6234
6250
  if (manifest.permission_class === PermissionClass.ACTION || manifest.permission_class === PermissionClass.PAYMENT) {
6235
6251
  if (!manifest.dry_run_supported) {
6236
6252
  issues.push("action/payment apps should support dry_run");
@@ -6279,12 +6295,6 @@ var AppTestHarness = class {
6279
6295
  }
6280
6296
  return issues;
6281
6297
  }
6282
- async simulate_connected_account_missing(task_type = "default", options = {}) {
6283
- return this.executeWithKind("dry_run", task_type, {
6284
- ...options,
6285
- connected_accounts: {}
6286
- });
6287
- }
6288
6298
  async simulate_metering(record, options = {}) {
6289
6299
  const { normalizeUsageRecord: normalizeUsageRecord2 } = await Promise.resolve().then(() => (init_metering(), metering_exports));
6290
6300
  const manifest = await this.app.manifest();
@@ -6312,7 +6322,7 @@ var AppTestHarness = class {
6312
6322
  };
6313
6323
  }
6314
6324
  return {
6315
- experimental: manifest.price_model === PriceModel.USAGE_BASED || manifest.price_model === PriceModel.PER_ACTION,
6325
+ experimental: false,
6316
6326
  usage_record,
6317
6327
  invoice_line_preview
6318
6328
  };
@@ -7247,15 +7257,6 @@ async function loadProject(path = ".") {
7247
7257
  const tool_manual = tool_manual_path ? JSON.parse(await (0, import_promises.readFile)(tool_manual_path, "utf8")) : buildToolManualTemplate(manifest);
7248
7258
  const runtime_validation_path = await findRuntimeValidationPath(root_dir);
7249
7259
  const runtime_validation = runtime_validation_path ? await loadJsonObject(runtime_validation_path, "runtime_validation") : void 0;
7250
- const oauth_credentials_path = await findOauthCredentialsPath(root_dir);
7251
- let oauth_credentials;
7252
- if (oauth_credentials_path) {
7253
- const parsed = JSON.parse(await (0, import_promises.readFile)(oauth_credentials_path, "utf8"));
7254
- if (!isRecord(parsed) && !Array.isArray(parsed)) {
7255
- throw new SiglumeProjectError("oauth_credentials must be a JSON object or array");
7256
- }
7257
- oauth_credentials = parsed;
7258
- }
7259
7260
  return {
7260
7261
  root_dir,
7261
7262
  adapter_path,
@@ -7264,9 +7265,7 @@ async function loadProject(path = ".") {
7264
7265
  tool_manual_path: tool_manual_path ?? void 0,
7265
7266
  tool_manual,
7266
7267
  runtime_validation_path: runtime_validation_path ?? void 0,
7267
- runtime_validation,
7268
- oauth_credentials_path: oauth_credentials_path ?? void 0,
7269
- oauth_credentials
7268
+ runtime_validation
7270
7269
  };
7271
7270
  }
7272
7271
  function isPlatformManagedRequirement(value) {
@@ -7304,6 +7303,21 @@ function requiredOauthProviders(requirements) {
7304
7303
  }
7305
7304
  return providers;
7306
7305
  }
7306
+ function apiManagedRequirementsMissingConnectUrl(requirements) {
7307
+ const missing = [];
7308
+ for (const item of requirements ?? []) {
7309
+ if (!isRecord(item)) continue;
7310
+ const managedBy = String(item.managed_by ?? "").trim().toLowerCase().replaceAll("_", "-");
7311
+ if (managedBy !== "api") continue;
7312
+ const connectUrl = String(item.connect_url ?? "").trim();
7313
+ if (connectUrl) continue;
7314
+ const label = oauthProviderKeyFromRequirement(item) ?? "(missing provider_key)";
7315
+ if (!missing.includes(label)) {
7316
+ missing.push(label);
7317
+ }
7318
+ }
7319
+ return missing;
7320
+ }
7307
7321
  function connectedAccountRequirementLabel(value) {
7308
7322
  if (isRecord(value)) {
7309
7323
  for (const key of ["provider_key", "provider", "account_type", "name"]) {
@@ -7314,102 +7328,6 @@ function connectedAccountRequirementLabel(value) {
7314
7328
  }
7315
7329
  return String(value ?? "").trim();
7316
7330
  }
7317
- function oauthProviderRecordsMap(payload) {
7318
- if (!payload) {
7319
- return {};
7320
- }
7321
- const items = Array.isArray(payload) ? payload : Array.isArray(payload.items) ? payload.items : [payload];
7322
- const resolved = {};
7323
- for (const [index, item] of items.entries()) {
7324
- if (!isRecord(item)) {
7325
- throw new SiglumeProjectError(`oauth_credentials[${index}] must be a JSON object.`);
7326
- }
7327
- const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
7328
- if (!providerKey) {
7329
- throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is required.`);
7330
- }
7331
- const authorizeUrl = String(item.authorize_url ?? item.authorization_url ?? item.auth_url ?? "").trim();
7332
- const tokenUrl = String(item.token_url ?? "").trim();
7333
- if (!authorizeUrl || !tokenUrl) {
7334
- throw new SiglumeProjectError(
7335
- `oauth_credentials[${index}] must include authorize_url and token_url.`
7336
- );
7337
- }
7338
- for (const [urlKey, urlValue] of Object.entries({
7339
- authorize_url: authorizeUrl,
7340
- token_url: tokenUrl,
7341
- revoke_url: String(item.revoke_url ?? "").trim()
7342
- })) {
7343
- if (urlValue && !urlValue.startsWith("https://")) {
7344
- throw new SiglumeProjectError(`oauth_credentials[${index}].${urlKey} must be an https URL.`);
7345
- }
7346
- }
7347
- const clientId = String(item.client_id ?? "").trim();
7348
- const clientSecret = String(item.client_secret ?? "").trim();
7349
- if (!clientId || !clientSecret) {
7350
- throw new SiglumeProjectError(`oauth_credentials[${index}] must include client_id and client_secret.`);
7351
- }
7352
- const rawScopes = item.required_scopes ?? item.scopes;
7353
- let scopes = [];
7354
- if (rawScopes == null) {
7355
- scopes = [];
7356
- } else if (!Array.isArray(rawScopes)) {
7357
- throw new SiglumeProjectError(`oauth_credentials[${index}].required_scopes must be a JSON array.`);
7358
- } else {
7359
- scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7360
- }
7361
- const record = {
7362
- provider_key: providerKey,
7363
- client_id: clientId,
7364
- client_secret: clientSecret,
7365
- required_scopes: scopes
7366
- };
7367
- for (const [key, value] of Object.entries({
7368
- authorize_url: authorizeUrl,
7369
- token_url: tokenUrl,
7370
- revoke_url: String(item.revoke_url ?? "").trim(),
7371
- display_name: String(item.display_name ?? "").trim(),
7372
- scope_separator: String(item.scope_separator ?? "").trim(),
7373
- token_endpoint_auth: String(item.token_endpoint_auth ?? "").trim()
7374
- })) {
7375
- if (value) record[key] = value;
7376
- }
7377
- for (const key of ["pkce_required", "refresh_supported"]) {
7378
- if (typeof item[key] === "boolean") record[key] = item[key];
7379
- }
7380
- if (Array.isArray(item.available_scopes)) {
7381
- const availableScopes = item.available_scopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7382
- if (availableScopes.length > 0) record.available_scopes = availableScopes;
7383
- }
7384
- resolved[providerKey] = record;
7385
- }
7386
- return resolved;
7387
- }
7388
- function canonicalOauthCredentialsPayload(payload) {
7389
- const records = oauthProviderRecordsMap(payload);
7390
- const providerKeys = Object.keys(records).sort();
7391
- if (providerKeys.length === 0) {
7392
- return void 0;
7393
- }
7394
- return {
7395
- items: providerKeys.map((providerKey) => records[providerKey])
7396
- };
7397
- }
7398
- function ensureRequiredOauthCredentials(project) {
7399
- const requiredProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
7400
- if (requiredProviders.length === 0) {
7401
- return;
7402
- }
7403
- const provided = new Set(Object.keys(oauthProviderRecordsMap(project.oauth_credentials)));
7404
- const missing = requiredProviders.filter((provider) => !provided.has(provider));
7405
- if (missing.length === 0) {
7406
- return;
7407
- }
7408
- const path = project.oauth_credentials_path ?? (0, import_node_path.join)(project.root_dir, "oauth_credentials.json");
7409
- throw new SiglumeProjectError(
7410
- `${path} is required for platform-managed OAuth APIs. Missing provider seeds: ${missing.join(", ")}`
7411
- );
7412
- }
7413
7331
  async function validateProject(path = ".", deps = {}) {
7414
7332
  const project = await loadProject(path);
7415
7333
  const manifest_issues = await projectValidationIssues(project);
@@ -7564,10 +7482,21 @@ function ensureExplicitToolManual(project) {
7564
7482
  async function registrationPreflight(project, client) {
7565
7483
  const manifestIssues = await projectValidationIssues(project);
7566
7484
  const [toolManualValid, toolManualIssues] = validate_tool_manual(project.tool_manual);
7485
+ const retiredPlatformOauthProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
7486
+ if (retiredPlatformOauthProviders.length > 0) {
7487
+ throw new SiglumeProjectError(
7488
+ `Registration preflight failed. Fix these before calling auto-register:
7489
+ - platform-managed OAuth is retired. Use managed_by="api" with connect_url: ${retiredPlatformOauthProviders.join(", ")}`
7490
+ );
7491
+ }
7492
+ const apiManagedMissingConnectUrl = apiManagedRequirementsMissingConnectUrl(project.manifest.required_connected_accounts ?? []);
7493
+ if (apiManagedMissingConnectUrl.length > 0) {
7494
+ throw new SiglumeProjectError(
7495
+ `Registration preflight failed. Fix these before calling auto-register:
7496
+ - API-managed OAuth requirements must include connect_url: ${apiManagedMissingConnectUrl.join(", ")}`
7497
+ );
7498
+ }
7567
7499
  const remoteQuality = await client.preview_quality_score(project.tool_manual);
7568
- const requiredOauthProvidersList = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
7569
- const oauthProviderRecords = oauthProviderRecordsMap(project.oauth_credentials);
7570
- const missingOauthProviders = requiredOauthProvidersList.filter((provider) => !oauthProviderRecords[provider]);
7571
7500
  const blockingToolManualIssues = toolManualIssues.filter((issue2) => issue2.severity === "error");
7572
7501
  const errors = [
7573
7502
  ...manifestIssues.map((issue2) => String(issue2)),
@@ -7579,17 +7508,12 @@ async function registrationPreflight(project, client) {
7579
7508
  if (!remoteQualityOk(remoteQuality)) {
7580
7509
  errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
7581
7510
  }
7582
- if (missingOauthProviders.length > 0) {
7583
- errors.push(`oauth_credentials.json is required for platform-managed OAuth APIs: ${missingOauthProviders.join(", ")}`);
7584
- }
7585
7511
  const preflight = {
7586
7512
  manifest_issues: manifestIssues,
7587
7513
  tool_manual_valid: toolManualValid,
7588
7514
  tool_manual_issues: toolManualIssues.map((issue2) => toJsonable(issue2)),
7589
7515
  remote_quality: toJsonable(remoteQuality),
7590
- required_oauth_providers: requiredOauthProvidersList,
7591
- oauth_credentials_path: project.oauth_credentials_path ?? null,
7592
- oauth_missing_providers: missingOauthProviders,
7516
+ retired_platform_oauth_providers: retiredPlatformOauthProviders,
7593
7517
  ok: errors.length === 0
7594
7518
  };
7595
7519
  if (errors.length > 0) {
@@ -7628,8 +7552,6 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7628
7552
  ensureExplicitToolManual(project);
7629
7553
  ensureManifestPublisherIdentity(project);
7630
7554
  ensureRuntimeValidationReady(project);
7631
- ensureRequiredOauthCredentials(project);
7632
- const canonicalOauthCredentials = canonicalOauthCredentialsPayload(project.oauth_credentials);
7633
7555
  const client = await createClient(deps);
7634
7556
  if (requestedCompanySlug) {
7635
7557
  const slug = companyNameSlug(requestedCompanySlug);
@@ -7706,14 +7628,12 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7706
7628
  }
7707
7629
  }
7708
7630
  const receipt = await client.auto_register(project.manifest, project.tool_manual, {
7709
- runtime_validation: project.runtime_validation,
7710
- oauth_credentials: canonicalOauthCredentials
7631
+ runtime_validation: project.runtime_validation
7711
7632
  });
7712
7633
  const result = {
7713
7634
  receipt: toJsonable(receipt),
7714
7635
  registration_preflight: preflight,
7715
- runtime_validation_path: project.runtime_validation_path ?? null,
7716
- oauth_credentials_path: project.oauth_credentials_path ?? null
7636
+ runtime_validation_path: project.runtime_validation_path ?? null
7717
7637
  };
7718
7638
  if (developerPortalPreflight) {
7719
7639
  result.developer_portal_preflight = developerPortalPreflight;
@@ -7734,7 +7654,6 @@ async function runPreflight(path = ".", deps = {}) {
7734
7654
  ensureExplicitToolManual(project);
7735
7655
  ensureManifestPublisherIdentity(project);
7736
7656
  ensureRuntimeValidationReady(project);
7737
- ensureRequiredOauthCredentials(project);
7738
7657
  const client = await createClient(deps);
7739
7658
  const preflight = await registrationPreflight(project, client);
7740
7659
  let developerPortalPreflight = null;
@@ -7752,8 +7671,7 @@ async function runPreflight(path = ".", deps = {}) {
7752
7671
  ok: true,
7753
7672
  adapter_path: project.adapter_path,
7754
7673
  registration_preflight: preflight,
7755
- runtime_validation_path: project.runtime_validation_path ?? null,
7756
- oauth_credentials_path: project.oauth_credentials_path ?? null
7674
+ runtime_validation_path: project.runtime_validation_path ?? null
7757
7675
  };
7758
7676
  if (developerPortalPreflight) {
7759
7677
  result.developer_portal_preflight = developerPortalPreflight;
@@ -8235,7 +8153,7 @@ function operationReadmeTemplate(operation, manifest, warning) {
8235
8153
  "- `tool_manual.json`: machine-generated ToolManual scaffold",
8236
8154
  "- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
8237
8155
  "- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
8238
- "- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
8156
+ "- `.gitignore`: keeps runtime review keys out of Git",
8239
8157
  "- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
8240
8158
  "",
8241
8159
  "Before registering, replace all generated placeholders:",
@@ -8243,8 +8161,8 @@ function operationReadmeTemplate(operation, manifest, warning) {
8243
8161
  "- Replace `support_contact` with a real support email address or public support URL.",
8244
8162
  "- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
8245
8163
  "- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
8246
- "- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
8247
- "- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
8164
+ "- If the API uses external OAuth, implement that flow in your API runtime and keep user tokens outside Siglume.",
8165
+ "- Do not commit real review keys or external-provider secrets; the generated `.gitignore` excludes local secret files.",
8248
8166
  "- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
8249
8167
  "",
8250
8168
  "## Commands",
@@ -8320,8 +8238,6 @@ function generatedGitignore() {
8320
8238
  "!.env.example",
8321
8239
  "runtime_validation.json",
8322
8240
  "runtime-validation.json",
8323
- "oauth_credentials.json",
8324
- "oauth-credentials.json",
8325
8241
  "",
8326
8242
  "# Python / test artifacts.",
8327
8243
  "__pycache__/",
@@ -8467,13 +8383,6 @@ async function runHarnessForProject(project) {
8467
8383
  checks.push(executionCheck("quote", await harness.execute_quote(task_type, { input_params: sample_input }), harness));
8468
8384
  checks.push(executionCheck("payment", await harness.execute_payment(task_type, { input_params: sample_input }), harness));
8469
8385
  }
8470
- checks.push(
8471
- executionCheck(
8472
- "missing_account_simulation",
8473
- await harness.simulate_connected_account_missing(task_type, { input_params: sample_input }),
8474
- harness
8475
- )
8476
- );
8477
8386
  return {
8478
8387
  adapter_path: project.adapter_path,
8479
8388
  task_type,
@@ -8576,15 +8485,6 @@ async function findRuntimeValidationPath(root_dir) {
8576
8485
  }
8577
8486
  return null;
8578
8487
  }
8579
- async function findOauthCredentialsPath(root_dir) {
8580
- for (const name of ["oauth_credentials.json", "oauth-credentials.json"]) {
8581
- const candidate = (0, import_node_path.join)(root_dir, name);
8582
- if ((0, import_node_fs.existsSync)(candidate)) {
8583
- return candidate;
8584
- }
8585
- }
8586
- return null;
8587
- }
8588
8488
  async function loadJsonObject(path, label) {
8589
8489
  let payload;
8590
8490
  try {
@@ -8816,15 +8716,15 @@ function readmeTemplate(template) {
8816
8716
  "- `tool_manual.json`: editable ToolManual draft for validation and registration",
8817
8717
  "- `runtime_validation.json`: local live API smoke-test contract used during registration",
8818
8718
  "- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
8819
- "- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
8719
+ "- `.gitignore`: keeps runtime review keys out of Git",
8820
8720
  "",
8821
8721
  "Before registering, replace all generated placeholders:",
8822
8722
  "- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
8823
8723
  "- Replace `support_contact` with a real support email address or public support URL.",
8824
8724
  "- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
8825
8725
  "- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
8826
- "- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
8827
- "- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
8726
+ "- If the API uses external OAuth, implement that flow in your API runtime and keep user tokens outside Siglume.",
8727
+ "- Do not commit real review keys or external-provider secrets; the generated `.gitignore` excludes local secret files.",
8828
8728
  "- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
8829
8729
  "",
8830
8730
  "Suggested workflow:",
@@ -9042,7 +8942,6 @@ async function runCli(argv, deps = {}) {
9042
8942
  emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
9043
8943
  }
9044
8944
  if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
9045
- if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
9046
8945
  });
9047
8946
  program.command("companies").description("List Siglume companies available for company-name publishing.").option("--json", "emit machine-readable JSON", false).action(async (options) => {
9048
8947
  const report = await listCompanyPublishersReport(deps);
@@ -9093,7 +8992,6 @@ async function runCli(argv, deps = {}) {
9093
8992
  emit(stdout, `listing_id: ${receipt.listing_id}`);
9094
8993
  emit(stdout, `receipt_status: ${receipt.status}`);
9095
8994
  if (receipt.listing_status) emit(stdout, `listing_status: ${receipt.listing_status}`);
9096
- if (receipt.oauth_status) emit(stdout, `oauth_configured: ${Boolean(receipt.oauth_status.configured)}`);
9097
8995
  if (receipt.review_url) emit(stdout, `review_url: ${receipt.review_url}`);
9098
8996
  if (receipt.trace_id) emit(stdout, `trace_id: ${receipt.trace_id}`);
9099
8997
  if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);