@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.
package/dist/index.cjs CHANGED
@@ -30,6 +30,81 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
+ // src/types.ts
34
+ var PermissionClass, ApprovalMode, ExecutionKind, Environment, PriceModel, AppCategory, StoreVertical, ListingCurrency, MINIMUM_JPY_OPERATION_PRICE_MINOR, PersistenceMode, ToolManualPermissionClass, SettlementMode;
35
+ var init_types = __esm({
36
+ "src/types.ts"() {
37
+ "use strict";
38
+ PermissionClass = {
39
+ READ_ONLY: "read-only",
40
+ ACTION: "action",
41
+ PAYMENT: "payment",
42
+ /** @deprecated Use READ_ONLY. Behaves identically. */
43
+ RECOMMENDATION: "recommendation"
44
+ };
45
+ ApprovalMode = {
46
+ AUTO: "auto",
47
+ BUDGET_BOUNDED: "budget-bounded",
48
+ ALWAYS_ASK: "always-ask",
49
+ DENY: "deny"
50
+ };
51
+ ExecutionKind = {
52
+ DRY_RUN: "dry_run",
53
+ QUOTE: "quote",
54
+ ACTION: "action",
55
+ PAYMENT: "payment"
56
+ };
57
+ Environment = {
58
+ SANDBOX: "sandbox",
59
+ LIVE: "live"
60
+ };
61
+ PriceModel = {
62
+ FREE: "free",
63
+ SUBSCRIPTION: "subscription",
64
+ ONE_TIME: "one_time",
65
+ BUNDLE: "bundle",
66
+ USAGE_BASED: "usage_based",
67
+ PER_ACTION: "per_action"
68
+ };
69
+ AppCategory = {
70
+ COMMERCE: "commerce",
71
+ BOOKING: "booking",
72
+ CRM: "crm",
73
+ FINANCE: "finance",
74
+ DOCUMENT: "document",
75
+ COMMUNICATION: "communication",
76
+ MONITORING: "monitoring",
77
+ OTHER: "other"
78
+ };
79
+ StoreVertical = {
80
+ API: "api",
81
+ GAME: "game"
82
+ };
83
+ ListingCurrency = {
84
+ USD: "USD",
85
+ JPY: "JPY"
86
+ };
87
+ MINIMUM_JPY_OPERATION_PRICE_MINOR = 15;
88
+ PersistenceMode = {
89
+ NONE: "none",
90
+ LOCAL: "local",
91
+ PLATFORM: "platform",
92
+ DEVELOPER_SERVER: "developer_server"
93
+ };
94
+ ToolManualPermissionClass = {
95
+ READ_ONLY: "read_only",
96
+ ACTION: "action",
97
+ PAYMENT: "payment"
98
+ };
99
+ SettlementMode = {
100
+ STRIPE_CHECKOUT: "stripe_checkout",
101
+ STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
102
+ POLYGON_MANDATE: "polygon_mandate",
103
+ EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
104
+ };
105
+ }
106
+ });
107
+
33
108
  // src/errors.ts
34
109
  var SiglumeError, SiglumeClientError, SiglumeProjectError, SiglumeValidationError, SiglumeAssistError, SiglumeNotFoundError, SiglumeWebhookError, SiglumeWebhookSignatureError, SiglumeWebhookPayloadError, SiglumeWebhookReplayError, SiglumeAPIError;
35
110
  var init_errors = __esm({
@@ -1609,6 +1684,58 @@ function validateSaveDataSchema(schema, fieldName) {
1609
1684
  }
1610
1685
  }
1611
1686
  }
1687
+ function validatePricingPlanFloor(plan, defaultCurrency) {
1688
+ if (plan === void 0 || plan === null) {
1689
+ return;
1690
+ }
1691
+ if (!isRecord2(plan)) {
1692
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
1693
+ }
1694
+ const items = plan.items;
1695
+ if (items === void 0 || items === null) {
1696
+ return;
1697
+ }
1698
+ if (!Array.isArray(items)) {
1699
+ throw new SiglumeClientError("AppManifest.pricing_plan.items must be an array when provided.");
1700
+ }
1701
+ const planCurrency = String(plan.currency ?? defaultCurrency ?? "").trim().toUpperCase();
1702
+ const seenKeys = /* @__PURE__ */ new Set();
1703
+ items.forEach((item, index) => {
1704
+ if (!isRecord2(item)) {
1705
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}] must be an object.`);
1706
+ }
1707
+ const itemKey = String(
1708
+ item.key ?? item.operation ?? item.operation_key ?? item.request_type ?? item.receipt_code ?? item.action ?? ""
1709
+ ).trim();
1710
+ if (!itemKey) {
1711
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key is required.`);
1712
+ }
1713
+ if (seenKeys.has(itemKey)) {
1714
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key duplicates ${itemKey}.`);
1715
+ }
1716
+ seenKeys.add(itemKey);
1717
+ const amountRaw = item.price_minor ?? item.amount_minor ?? item.cost_minor ?? item.value_minor;
1718
+ if (amountRaw === void 0 || amountRaw === null) {
1719
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor is required.`);
1720
+ }
1721
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
1722
+ if (!Number.isInteger(amountMinor)) {
1723
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be an integer.`);
1724
+ }
1725
+ if (amountMinor < 0) {
1726
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be zero or positive.`);
1727
+ }
1728
+ const currency = String(item.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
1729
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
1730
+ throw new SiglumeClientError(
1731
+ `AppManifest.pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing.`
1732
+ );
1733
+ }
1734
+ });
1735
+ }
1736
+ function pricingPlanHasItems(plan) {
1737
+ return isRecord2(plan) && Array.isArray(plan.items) && plan.items.length > 0;
1738
+ }
1612
1739
  function buildToolManualQualityReport(payload) {
1613
1740
  const qualityBlock = isRecord2(payload.quality) ? payload.quality : payload;
1614
1741
  const issues = [];
@@ -1684,6 +1811,7 @@ function buildUrl(baseUrl, path, params) {
1684
1811
  }
1685
1812
  function parseListing(data) {
1686
1813
  const metadata = isRecord2(data.metadata) ? data.metadata : {};
1814
+ const pricing_plan = isRecord2(data.pricing_plan) ? data.pricing_plan : isRecord2(metadata.pricing_plan) ? metadata.pricing_plan : null;
1687
1815
  const persistence = isRecord2(data.persistence) ? data.persistence : isRecord2(metadata.persistence) ? metadata.persistence : {};
1688
1816
  return {
1689
1817
  listing_id: String(data.listing_id ?? data.id ?? ""),
@@ -1697,6 +1825,7 @@ function parseListing(data) {
1697
1825
  dry_run_supported: Boolean(data.dry_run_supported ?? false),
1698
1826
  price_model: stringOrNull2(data.price_model),
1699
1827
  price_value_minor: Number(data.price_value_minor ?? 0),
1828
+ pricing_plan,
1700
1829
  currency: String(data.currency ?? "USD"),
1701
1830
  allow_free_trial: Boolean(data.allow_free_trial ?? false),
1702
1831
  free_trial_duration_days: Number(data.free_trial_duration_days ?? 30),
@@ -1771,18 +1900,6 @@ function parseBundleMember(data) {
1771
1900
  link_id: stringOrNull2(data.link_id)
1772
1901
  };
1773
1902
  }
1774
- function parseConnectedAccountLifecycle(data) {
1775
- return {
1776
- connected_account_id: String(data.connected_account_id ?? ""),
1777
- provider_key: String(data.provider_key ?? ""),
1778
- expires_at: stringOrNull2(data.expires_at),
1779
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((s) => typeof s === "string") : [],
1780
- refreshed_at: stringOrNull2(data.refreshed_at),
1781
- connection_status: stringOrNull2(data.connection_status),
1782
- provider_revoked: typeof data.provider_revoked === "boolean" ? data.provider_revoked : null,
1783
- revoked_at: stringOrNull2(data.revoked_at)
1784
- };
1785
- }
1786
1903
  function parseBundle(data) {
1787
1904
  const membersRaw = Array.isArray(data.members) ? data.members : [];
1788
1905
  return {
@@ -1861,21 +1978,6 @@ function parseBinding(data) {
1861
1978
  raw: { ...data }
1862
1979
  };
1863
1980
  }
1864
- function parseConnectedAccount(data) {
1865
- return {
1866
- connected_account_id: String(data.connected_account_id ?? data.id ?? ""),
1867
- provider_key: String(data.provider_key ?? ""),
1868
- account_role: String(data.account_role ?? ""),
1869
- display_name: stringOrNull2(data.display_name),
1870
- environment: stringOrNull2(data.environment),
1871
- connection_status: stringOrNull2(data.connection_status),
1872
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((item) => typeof item === "string") : [],
1873
- metadata: toRecord2(data.metadata),
1874
- created_at: stringOrNull2(data.created_at),
1875
- updated_at: stringOrNull2(data.updated_at),
1876
- raw: { ...data }
1877
- };
1878
- }
1879
1981
  function parseSupportCase(data) {
1880
1982
  return {
1881
1983
  support_case_id: String(data.support_case_id ?? data.id ?? ""),
@@ -2821,10 +2923,11 @@ function cloneJsonLike(value) {
2821
2923
  }
2822
2924
  return value;
2823
2925
  }
2824
- var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, CursorPageResult, SiglumeClient;
2926
+ var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, MINIMUM_JPY_OPERATION_PRICE_CURRENCIES, CursorPageResult, SiglumeClient;
2825
2927
  var init_client = __esm({
2826
2928
  "src/client.ts"() {
2827
2929
  "use strict";
2930
+ init_types();
2828
2931
  init_errors();
2829
2932
  init_webhooks();
2830
2933
  init_web3();
@@ -2832,6 +2935,7 @@ var init_client = __esm({
2832
2935
  init_utils();
2833
2936
  DEFAULT_SIGLUME_API_BASE = "https://siglume.com/v1";
2834
2937
  RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
2938
+ MINIMUM_JPY_OPERATION_PRICE_CURRENCIES = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
2835
2939
  CursorPageResult = class {
2836
2940
  items;
2837
2941
  next_cursor;
@@ -2914,13 +3018,6 @@ var init_client = __esm({
2914
3018
  if (options.runtime_validation) {
2915
3019
  payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
2916
3020
  }
2917
- if (options.oauth_credentials) {
2918
- payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
2919
- items: options.oauth_credentials.map(
2920
- (item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
2921
- )
2922
- } : coerceMapping(options.oauth_credentials, "oauth_credentials");
2923
- }
2924
3021
  if (options.source_context) {
2925
3022
  payload.source_context = coerceMapping(options.source_context, "source_context");
2926
3023
  }
@@ -2946,6 +3043,7 @@ var init_client = __esm({
2946
3043
  "jurisdiction",
2947
3044
  "price_model",
2948
3045
  "price_value_minor",
3046
+ "pricing_plan",
2949
3047
  "currency",
2950
3048
  "allow_free_trial",
2951
3049
  "free_trial_duration_days",
@@ -2962,6 +3060,9 @@ var init_client = __esm({
2962
3060
  payload[fieldName] = value;
2963
3061
  }
2964
3062
  }
3063
+ if (payload.pricing_plan !== void 0 && (typeof payload.pricing_plan !== "object" || Array.isArray(payload.pricing_plan))) {
3064
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
3065
+ }
2965
3066
  if (payload.store_vertical === void 0 || payload.store_vertical === null) {
2966
3067
  throw new SiglumeClientError(
2967
3068
  "AppManifest.store_vertical is required. Choose 'api' for normal API Store listings or 'game' for API games."
@@ -2977,6 +3078,13 @@ var init_client = __esm({
2977
3078
  throw new SiglumeClientError(`AppManifest.currency must be 'USD' or 'JPY'. Got ${String(payload.currency)}.`);
2978
3079
  }
2979
3080
  payload.currency = currency;
3081
+ if (payload.pricing_plan !== void 0) {
3082
+ validatePricingPlanFloor(payload.pricing_plan, currency);
3083
+ }
3084
+ const priceModel = String(payload.price_model ?? "free").trim().toLowerCase();
3085
+ if ((priceModel === "usage_based" || priceModel === "per_action") && !pricingPlanHasItems(payload.pricing_plan)) {
3086
+ throw new SiglumeClientError("AppManifest.pricing_plan.items is required for usage_based/per_action pricing.");
3087
+ }
2980
3088
  if (payload.allow_free_trial === void 0 || payload.allow_free_trial === null) {
2981
3089
  throw new SiglumeClientError(
2982
3090
  "AppManifest.allow_free_trial is required. Pass true to offer a Plus/Pro buyer free trial or false to disable trials."
@@ -3050,7 +3158,6 @@ var init_client = __esm({
3050
3158
  auto_manifest: toRecord2(data.auto_manifest),
3051
3159
  confidence: toRecord2(data.confidence),
3052
3160
  validation_report: toRecord2(data.validation_report),
3053
- oauth_status: toRecord2(data.oauth_status),
3054
3161
  review_url: stringOrNull2(data.review_url),
3055
3162
  trace_id: meta.trace_id,
3056
3163
  request_id: meta.request_id
@@ -3226,66 +3333,9 @@ var init_client = __esm({
3226
3333
  return parseBundle(data);
3227
3334
  }
3228
3335
  // ----- end bundles -------------------------------------------------------
3229
- // ----- Connected accounts (v0.7 track 3) ---------------------------------
3230
- // `resolve()` is intentionally NOT wrapped: runtime-only, never over the wire.
3231
- async start_connected_account_oauth(input) {
3232
- const body = {
3233
- listing_id: input.listing_id,
3234
- redirect_uri: input.redirect_uri
3235
- };
3236
- if (input.scopes !== void 0) body.scopes = input.scopes;
3237
- if (input.account_role !== void 0) body.account_role = input.account_role;
3238
- const [data] = await this.request("POST", "/me/connected-accounts/oauth/authorize", {
3239
- json_body: body
3240
- });
3241
- return {
3242
- authorize_url: String(data.authorize_url ?? ""),
3243
- state: String(data.state ?? ""),
3244
- provider_key: String(data.provider_key ?? ""),
3245
- scopes: Array.isArray(data.scopes) ? data.scopes.filter((s) => typeof s === "string") : [],
3246
- pkce_method: stringOrNull2(data.pkce_method)
3247
- };
3248
- }
3249
- async complete_connected_account_oauth(input) {
3250
- const [data] = await this.request("POST", "/me/connected-accounts/oauth/callback", {
3251
- json_body: { state: input.state, code: input.code }
3252
- });
3253
- return { ...data };
3254
- }
3255
- async refresh_connected_account(account_id) {
3256
- const [data] = await this.request("POST", `/me/connected-accounts/${account_id}/refresh`);
3257
- return parseConnectedAccountLifecycle(data);
3258
- }
3259
- async revoke_connected_account(account_id) {
3260
- const [data] = await this.request("POST", `/me/connected-accounts/${account_id}/revoke`);
3261
- return parseConnectedAccountLifecycle(data);
3262
- }
3263
- async set_listing_oauth_credentials(listing_id, input) {
3264
- const body = {
3265
- provider_key: input.provider_key,
3266
- client_id: input.client_id,
3267
- client_secret: input.client_secret,
3268
- authorize_url: input.authorize_url,
3269
- token_url: input.token_url
3270
- };
3271
- if (input.revoke_url !== void 0) body.revoke_url = input.revoke_url;
3272
- if (input.display_name !== void 0) body.display_name = input.display_name;
3273
- if (input.scope_separator !== void 0) body.scope_separator = input.scope_separator;
3274
- if (input.token_endpoint_auth !== void 0) body.token_endpoint_auth = input.token_endpoint_auth;
3275
- if (input.pkce_required !== void 0) body.pkce_required = input.pkce_required;
3276
- if (input.refresh_supported !== void 0) body.refresh_supported = input.refresh_supported;
3277
- if (input.available_scopes !== void 0) body.available_scopes = input.available_scopes;
3278
- if (input.required_scopes !== void 0) body.required_scopes = input.required_scopes;
3279
- const [data] = await this.request("PUT", `/market/capabilities/${listing_id}/oauth-credentials`, {
3280
- json_body: body
3281
- });
3282
- return { ...data };
3283
- }
3284
- async get_listing_oauth_credentials_status(listing_id) {
3285
- const [data] = await this.request("GET", `/market/capabilities/${listing_id}/oauth-credentials`);
3286
- return { ...data };
3287
- }
3288
- // ----- end connected accounts --------------------------------------------
3336
+ // ----- Connected accounts ------------------------------------------------
3337
+ // Architecture B: publisher APIs own external OAuth and token storage.
3338
+ // The SDK no longer exposes platform OAuth or listing credential APIs.
3289
3339
  async get_developer_portal() {
3290
3340
  const [data, meta] = await this.request("GET", "/market/developer/portal");
3291
3341
  return {
@@ -3318,7 +3368,6 @@ var init_client = __esm({
3318
3368
  dry_run_supported: Boolean(data.dry_run_supported ?? false),
3319
3369
  approval_mode: stringOrNull2(data.approval_mode),
3320
3370
  required_connected_accounts: Array.isArray(data.required_connected_accounts) ? data.required_connected_accounts : [],
3321
- connected_accounts: Array.isArray(data.connected_accounts) ? data.connected_accounts.filter((item) => isRecord2(item)).map((item) => ({ ...item })) : [],
3322
3371
  stub_providers_enabled: Boolean(data.stub_providers_enabled ?? false),
3323
3372
  simulated_receipts: Boolean(data.simulated_receipts ?? false),
3324
3373
  approval_simulator: Boolean(data.approval_simulator ?? false),
@@ -4616,25 +4665,6 @@ var init_client = __esm({
4616
4665
  raw: { ...data }
4617
4666
  };
4618
4667
  }
4619
- async list_connected_accounts(options = {}) {
4620
- const params = {
4621
- provider_key: options.provider_key,
4622
- environment: options.environment,
4623
- limit: Math.max(1, Math.min(Math.trunc(options.limit ?? 50), 100)),
4624
- cursor: options.cursor
4625
- };
4626
- const [data, meta] = await this.request("GET", "/market/connected-accounts", { params });
4627
- const items = Array.isArray(data.items) ? data.items.filter((item) => isRecord2(item)).map(parseConnectedAccount) : [];
4628
- const next_cursor = stringOrNull2(data.next_cursor);
4629
- return new CursorPageResult({
4630
- items,
4631
- next_cursor,
4632
- limit: typeof data.limit === "number" ? data.limit : params.limit,
4633
- offset: typeof data.offset === "number" ? data.offset : null,
4634
- meta,
4635
- fetchNext: next_cursor ? (cursor) => this.list_connected_accounts({ ...options, cursor }) : void 0
4636
- });
4637
- }
4638
4668
  async create_support_case(subject, body, options = {}) {
4639
4669
  const summary = subject.trim();
4640
4670
  const details = body.trim();
@@ -5317,6 +5347,7 @@ __export(src_exports, {
5317
5347
  InMemoryWebhookDedupe: () => InMemoryWebhookDedupe,
5318
5348
  LLMProvider: () => LLMProvider,
5319
5349
  ListingCurrency: () => ListingCurrency,
5350
+ MINIMUM_JPY_OPERATION_PRICE_MINOR: () => MINIMUM_JPY_OPERATION_PRICE_MINOR,
5320
5351
  MeterClient: () => MeterClient,
5321
5352
  OpenAIProvider: () => OpenAIProvider,
5322
5353
  PermissionClass: () => PermissionClass,
@@ -6681,73 +6712,8 @@ function toRecord3(value) {
6681
6712
  init_metering();
6682
6713
  init_operations();
6683
6714
 
6684
- // src/types.ts
6685
- var PermissionClass = {
6686
- READ_ONLY: "read-only",
6687
- ACTION: "action",
6688
- PAYMENT: "payment",
6689
- /** @deprecated Use READ_ONLY. Behaves identically. */
6690
- RECOMMENDATION: "recommendation"
6691
- };
6692
- var ApprovalMode = {
6693
- AUTO: "auto",
6694
- BUDGET_BOUNDED: "budget-bounded",
6695
- ALWAYS_ASK: "always-ask",
6696
- DENY: "deny"
6697
- };
6698
- var ExecutionKind = {
6699
- DRY_RUN: "dry_run",
6700
- QUOTE: "quote",
6701
- ACTION: "action",
6702
- PAYMENT: "payment"
6703
- };
6704
- var Environment = {
6705
- SANDBOX: "sandbox",
6706
- LIVE: "live"
6707
- };
6708
- var PriceModel = {
6709
- FREE: "free",
6710
- SUBSCRIPTION: "subscription",
6711
- ONE_TIME: "one_time",
6712
- BUNDLE: "bundle",
6713
- USAGE_BASED: "usage_based",
6714
- PER_ACTION: "per_action"
6715
- };
6716
- var AppCategory = {
6717
- COMMERCE: "commerce",
6718
- BOOKING: "booking",
6719
- CRM: "crm",
6720
- FINANCE: "finance",
6721
- DOCUMENT: "document",
6722
- COMMUNICATION: "communication",
6723
- MONITORING: "monitoring",
6724
- OTHER: "other"
6725
- };
6726
- var StoreVertical = {
6727
- API: "api",
6728
- GAME: "game"
6729
- };
6730
- var ListingCurrency = {
6731
- USD: "USD",
6732
- JPY: "JPY"
6733
- };
6734
- var PersistenceMode = {
6735
- NONE: "none",
6736
- LOCAL: "local",
6737
- PLATFORM: "platform",
6738
- DEVELOPER_SERVER: "developer_server"
6739
- };
6740
- var ToolManualPermissionClass = {
6741
- READ_ONLY: "read_only",
6742
- ACTION: "action",
6743
- PAYMENT: "payment"
6744
- };
6745
- var SettlementMode = {
6746
- STRIPE_CHECKOUT: "stripe_checkout",
6747
- STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
6748
- POLYGON_MANDATE: "polygon_mandate",
6749
- EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
6750
- };
6715
+ // src/runtime.ts
6716
+ init_types();
6751
6717
 
6752
6718
  // src/testing/recorder.ts
6753
6719
  var CASSETTE_VERSION = 1;
@@ -7145,6 +7111,7 @@ Actual: ${requestSignature(requestRecord, ignoreBodyFields)}`
7145
7111
  };
7146
7112
 
7147
7113
  // src/tool-manual-validator.ts
7114
+ init_types();
7148
7115
  init_utils();
7149
7116
  var JURISDICTION_PATTERN = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/;
7150
7117
  var TOOL_NAME_RE = /^[A-Za-z0-9_]{3,64}$/;
@@ -7419,6 +7386,64 @@ function validate_tool_manual(manualInput) {
7419
7386
  // src/runtime.ts
7420
7387
  init_web3();
7421
7388
  var CAPABILITY_KEY_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
7389
+ var MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2 = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
7390
+ function pricingPlanFloorIssues(plan, defaultCurrency) {
7391
+ const issues = [];
7392
+ if (plan === void 0 || plan === null) {
7393
+ return issues;
7394
+ }
7395
+ if (typeof plan !== "object" || Array.isArray(plan)) {
7396
+ return ["pricing_plan must be an object when provided"];
7397
+ }
7398
+ const record = plan;
7399
+ const items = record.items;
7400
+ if (items === void 0 || items === null) {
7401
+ return issues;
7402
+ }
7403
+ if (!Array.isArray(items)) {
7404
+ return ["pricing_plan.items must be an array when provided"];
7405
+ }
7406
+ const planCurrency = String(record.currency ?? defaultCurrency ?? "").trim().toUpperCase();
7407
+ const seenKeys = /* @__PURE__ */ new Set();
7408
+ items.forEach((item, index) => {
7409
+ if (typeof item !== "object" || item === null || Array.isArray(item)) {
7410
+ issues.push(`pricing_plan.items[${index}] must be an object`);
7411
+ return;
7412
+ }
7413
+ const itemRecord = item;
7414
+ const itemKey = String(
7415
+ itemRecord.key ?? itemRecord.operation ?? itemRecord.operation_key ?? itemRecord.request_type ?? itemRecord.receipt_code ?? itemRecord.action ?? ""
7416
+ ).trim();
7417
+ if (!itemKey) {
7418
+ issues.push(`pricing_plan.items[${index}].key is required`);
7419
+ } else if (seenKeys.has(itemKey)) {
7420
+ issues.push(`pricing_plan.items[${index}].key duplicates ${itemKey}`);
7421
+ } else {
7422
+ seenKeys.add(itemKey);
7423
+ }
7424
+ const amountRaw = itemRecord.price_minor ?? itemRecord.amount_minor ?? itemRecord.cost_minor ?? itemRecord.value_minor;
7425
+ if (amountRaw === void 0 || amountRaw === null) {
7426
+ issues.push(`pricing_plan.items[${index}].price_minor is required`);
7427
+ return;
7428
+ }
7429
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
7430
+ if (!Number.isInteger(amountMinor)) {
7431
+ issues.push(`pricing_plan.items[${index}].price_minor must be an integer`);
7432
+ return;
7433
+ }
7434
+ if (amountMinor < 0) {
7435
+ issues.push(`pricing_plan.items[${index}].price_minor must be zero or positive`);
7436
+ return;
7437
+ }
7438
+ const currency = String(itemRecord.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
7439
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
7440
+ issues.push(
7441
+ `pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing`
7442
+ );
7443
+ }
7444
+ });
7445
+ return issues;
7446
+ }
7422
7447
  function normalizeExecutionResult(result, executionKind) {
7423
7448
  return {
7424
7449
  success: Boolean(result.success),
@@ -7473,24 +7498,12 @@ var AppTestHarness = class {
7473
7498
  this.stubs = stubs;
7474
7499
  }
7475
7500
  async executeWithKind(execution_kind, task_type = "default", options = {}) {
7476
- const connected_accounts = options.connected_accounts ?? Object.fromEntries(
7477
- Object.keys(this.stubs).map((key) => [
7478
- key,
7479
- {
7480
- provider_key: key,
7481
- session_token: `stub-token-${key}`,
7482
- environment: Environment.SANDBOX,
7483
- scopes: []
7484
- }
7485
- ])
7486
- );
7487
7501
  const ctx = {
7488
7502
  agent_id: "test-agent-001",
7489
7503
  owner_user_id: "test-owner-001",
7490
7504
  task_type,
7491
7505
  environment: Environment.SANDBOX,
7492
7506
  execution_kind,
7493
- connected_accounts,
7494
7507
  input_params: options.input_params ?? {},
7495
7508
  trace_id: options.trace_id,
7496
7509
  idempotency_key: options.idempotency_key,
@@ -7532,6 +7545,10 @@ var AppTestHarness = class {
7532
7545
  if (!manifest.example_prompts || manifest.example_prompts.length === 0) {
7533
7546
  issues.push("at least one example_prompt is recommended");
7534
7547
  }
7548
+ issues.push(...pricingPlanFloorIssues(manifest.pricing_plan, String(manifest.currency ?? "USD")));
7549
+ 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)) {
7550
+ issues.push("pricing_plan.items is required for usage_based/per_action pricing");
7551
+ }
7535
7552
  if (manifest.permission_class === PermissionClass.ACTION || manifest.permission_class === PermissionClass.PAYMENT) {
7536
7553
  if (!manifest.dry_run_supported) {
7537
7554
  issues.push("action/payment apps should support dry_run");
@@ -7580,12 +7597,6 @@ var AppTestHarness = class {
7580
7597
  }
7581
7598
  return issues;
7582
7599
  }
7583
- async simulate_connected_account_missing(task_type = "default", options = {}) {
7584
- return this.executeWithKind("dry_run", task_type, {
7585
- ...options,
7586
- connected_accounts: {}
7587
- });
7588
- }
7589
7600
  async simulate_metering(record, options = {}) {
7590
7601
  const { normalizeUsageRecord: normalizeUsageRecord2 } = await Promise.resolve().then(() => (init_metering(), metering_exports));
7591
7602
  const manifest = await this.app.manifest();
@@ -7613,7 +7624,7 @@ var AppTestHarness = class {
7613
7624
  };
7614
7625
  }
7615
7626
  return {
7616
- experimental: manifest.price_model === PriceModel.USAGE_BASED || manifest.price_model === PriceModel.PER_ACTION,
7627
+ experimental: false,
7617
7628
  usage_record,
7618
7629
  invoice_line_preview
7619
7630
  };
@@ -9039,6 +9050,7 @@ function readEnv(name) {
9039
9050
  }
9040
9051
 
9041
9052
  // src/index.ts
9053
+ init_types();
9042
9054
  init_web3();
9043
9055
  init_webhooks();
9044
9056
  init_utils();