@siglume/api-sdk 1.0.0 → 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.
@@ -178,6 +178,7 @@ interface AppManifest {
178
178
  permission_scopes?: string[];
179
179
  price_model?: PriceModel;
180
180
  price_value_minor?: number;
181
+ pricing_plan?: PricingPlan;
181
182
  currency: ListingCurrency;
182
183
  allow_free_trial: boolean;
183
184
  free_trial_duration_days?: number;
@@ -261,6 +262,28 @@ interface EnvelopeMeta {
261
262
  request_id?: string | null;
262
263
  trace_id?: string | null;
263
264
  }
265
+ interface PricingPlanItem {
266
+ key?: string | null;
267
+ label?: string | null;
268
+ price_minor?: number | null;
269
+ amount_minor?: number | null;
270
+ currency?: string | null;
271
+ unit_label?: string | null;
272
+ description?: string | null;
273
+ conditions?: unknown;
274
+ receipt_code?: string | null;
275
+ }
276
+ interface PricingPlan {
277
+ billing_model?: string | null;
278
+ display_name?: string | null;
279
+ summary?: string | null;
280
+ description?: string | null;
281
+ currency?: string | null;
282
+ unit_label?: string | null;
283
+ free_upfront_invocation?: boolean | null;
284
+ fallback_note?: string | null;
285
+ items?: PricingPlanItem[];
286
+ }
264
287
  interface CursorPage<T> {
265
288
  items: T[];
266
289
  next_cursor?: string | null;
@@ -282,6 +305,7 @@ interface AppListingRecord {
282
305
  dry_run_supported: boolean;
283
306
  price_model?: string | null;
284
307
  price_value_minor: number;
308
+ pricing_plan?: PricingPlan | null;
285
309
  currency: string;
286
310
  allow_free_trial: boolean;
287
311
  free_trial_duration_days: number;
@@ -178,6 +178,7 @@ interface AppManifest {
178
178
  permission_scopes?: string[];
179
179
  price_model?: PriceModel;
180
180
  price_value_minor?: number;
181
+ pricing_plan?: PricingPlan;
181
182
  currency: ListingCurrency;
182
183
  allow_free_trial: boolean;
183
184
  free_trial_duration_days?: number;
@@ -261,6 +262,28 @@ interface EnvelopeMeta {
261
262
  request_id?: string | null;
262
263
  trace_id?: string | null;
263
264
  }
265
+ interface PricingPlanItem {
266
+ key?: string | null;
267
+ label?: string | null;
268
+ price_minor?: number | null;
269
+ amount_minor?: number | null;
270
+ currency?: string | null;
271
+ unit_label?: string | null;
272
+ description?: string | null;
273
+ conditions?: unknown;
274
+ receipt_code?: string | null;
275
+ }
276
+ interface PricingPlan {
277
+ billing_model?: string | null;
278
+ display_name?: string | null;
279
+ summary?: string | null;
280
+ description?: string | null;
281
+ currency?: string | null;
282
+ unit_label?: string | null;
283
+ free_upfront_invocation?: boolean | null;
284
+ fallback_note?: string | null;
285
+ items?: PricingPlanItem[];
286
+ }
264
287
  interface CursorPage<T> {
265
288
  items: T[];
266
289
  next_cursor?: string | null;
@@ -282,6 +305,7 @@ interface AppListingRecord {
282
305
  dry_run_supported: boolean;
283
306
  price_model?: string | null;
284
307
  price_value_minor: number;
308
+ pricing_plan?: PricingPlan | null;
285
309
  currency: string;
286
310
  allow_free_trial: boolean;
287
311
  free_trial_duration_days: number;
package/dist/cli/index.js CHANGED
@@ -155,6 +155,61 @@ var init_utils = __esm({
155
155
  }
156
156
  });
157
157
 
158
+ // src/types.ts
159
+ var PermissionClass, ApprovalMode, Environment, PriceModel, AppCategory, MINIMUM_JPY_OPERATION_PRICE_MINOR, ToolManualPermissionClass, SettlementMode;
160
+ var init_types = __esm({
161
+ "src/types.ts"() {
162
+ "use strict";
163
+ PermissionClass = {
164
+ READ_ONLY: "read-only",
165
+ ACTION: "action",
166
+ PAYMENT: "payment",
167
+ /** @deprecated Use READ_ONLY. Behaves identically. */
168
+ RECOMMENDATION: "recommendation"
169
+ };
170
+ ApprovalMode = {
171
+ AUTO: "auto",
172
+ BUDGET_BOUNDED: "budget-bounded",
173
+ ALWAYS_ASK: "always-ask",
174
+ DENY: "deny"
175
+ };
176
+ Environment = {
177
+ SANDBOX: "sandbox",
178
+ LIVE: "live"
179
+ };
180
+ PriceModel = {
181
+ FREE: "free",
182
+ SUBSCRIPTION: "subscription",
183
+ ONE_TIME: "one_time",
184
+ BUNDLE: "bundle",
185
+ USAGE_BASED: "usage_based",
186
+ PER_ACTION: "per_action"
187
+ };
188
+ AppCategory = {
189
+ COMMERCE: "commerce",
190
+ BOOKING: "booking",
191
+ CRM: "crm",
192
+ FINANCE: "finance",
193
+ DOCUMENT: "document",
194
+ COMMUNICATION: "communication",
195
+ MONITORING: "monitoring",
196
+ OTHER: "other"
197
+ };
198
+ MINIMUM_JPY_OPERATION_PRICE_MINOR = 15;
199
+ ToolManualPermissionClass = {
200
+ READ_ONLY: "read_only",
201
+ ACTION: "action",
202
+ PAYMENT: "payment"
203
+ };
204
+ SettlementMode = {
205
+ STRIPE_CHECKOUT: "stripe_checkout",
206
+ STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
207
+ POLYGON_MANDATE: "polygon_mandate",
208
+ EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
209
+ };
210
+ }
211
+ });
212
+
158
213
  // src/webhooks.ts
159
214
  function isRecord2(value) {
160
215
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1276,6 +1331,58 @@ function validateSaveDataSchema(schema, fieldName) {
1276
1331
  }
1277
1332
  }
1278
1333
  }
1334
+ function validatePricingPlanFloor(plan, defaultCurrency) {
1335
+ if (plan === void 0 || plan === null) {
1336
+ return;
1337
+ }
1338
+ if (!isRecord(plan)) {
1339
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
1340
+ }
1341
+ const items = plan.items;
1342
+ if (items === void 0 || items === null) {
1343
+ return;
1344
+ }
1345
+ if (!Array.isArray(items)) {
1346
+ throw new SiglumeClientError("AppManifest.pricing_plan.items must be an array when provided.");
1347
+ }
1348
+ const planCurrency = String(plan.currency ?? defaultCurrency ?? "").trim().toUpperCase();
1349
+ const seenKeys = /* @__PURE__ */ new Set();
1350
+ items.forEach((item, index) => {
1351
+ if (!isRecord(item)) {
1352
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}] must be an object.`);
1353
+ }
1354
+ const itemKey = String(
1355
+ item.key ?? item.operation ?? item.operation_key ?? item.request_type ?? item.receipt_code ?? item.action ?? ""
1356
+ ).trim();
1357
+ if (!itemKey) {
1358
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key is required.`);
1359
+ }
1360
+ if (seenKeys.has(itemKey)) {
1361
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].key duplicates ${itemKey}.`);
1362
+ }
1363
+ seenKeys.add(itemKey);
1364
+ const amountRaw = item.price_minor ?? item.amount_minor ?? item.cost_minor ?? item.value_minor;
1365
+ if (amountRaw === void 0 || amountRaw === null) {
1366
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor is required.`);
1367
+ }
1368
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
1369
+ if (!Number.isInteger(amountMinor)) {
1370
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be an integer.`);
1371
+ }
1372
+ if (amountMinor < 0) {
1373
+ throw new SiglumeClientError(`AppManifest.pricing_plan.items[${index}].price_minor must be zero or positive.`);
1374
+ }
1375
+ const currency = String(item.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
1376
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
1377
+ throw new SiglumeClientError(
1378
+ `AppManifest.pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing.`
1379
+ );
1380
+ }
1381
+ });
1382
+ }
1383
+ function pricingPlanHasItems(plan) {
1384
+ return isRecord(plan) && Array.isArray(plan.items) && plan.items.length > 0;
1385
+ }
1279
1386
  function buildToolManualQualityReport(payload) {
1280
1387
  const qualityBlock = isRecord(payload.quality) ? payload.quality : payload;
1281
1388
  const issues = [];
@@ -1351,6 +1458,7 @@ function buildUrl(baseUrl, path, params) {
1351
1458
  }
1352
1459
  function parseListing(data) {
1353
1460
  const metadata = isRecord(data.metadata) ? data.metadata : {};
1461
+ const pricing_plan = isRecord(data.pricing_plan) ? data.pricing_plan : isRecord(metadata.pricing_plan) ? metadata.pricing_plan : null;
1354
1462
  const persistence = isRecord(data.persistence) ? data.persistence : isRecord(metadata.persistence) ? metadata.persistence : {};
1355
1463
  return {
1356
1464
  listing_id: String(data.listing_id ?? data.id ?? ""),
@@ -1364,6 +1472,7 @@ function parseListing(data) {
1364
1472
  dry_run_supported: Boolean(data.dry_run_supported ?? false),
1365
1473
  price_model: stringOrNull(data.price_model),
1366
1474
  price_value_minor: Number(data.price_value_minor ?? 0),
1475
+ pricing_plan,
1367
1476
  currency: String(data.currency ?? "USD"),
1368
1477
  allow_free_trial: Boolean(data.allow_free_trial ?? false),
1369
1478
  free_trial_duration_days: Number(data.free_trial_duration_days ?? 30),
@@ -2461,10 +2570,11 @@ function cloneJsonLike(value) {
2461
2570
  }
2462
2571
  return value;
2463
2572
  }
2464
- var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, CursorPageResult, SiglumeClient;
2573
+ var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, MINIMUM_JPY_OPERATION_PRICE_CURRENCIES, CursorPageResult, SiglumeClient;
2465
2574
  var init_client = __esm({
2466
2575
  "src/client.ts"() {
2467
2576
  "use strict";
2577
+ init_types();
2468
2578
  init_errors();
2469
2579
  init_webhooks();
2470
2580
  init_web3();
@@ -2472,6 +2582,7 @@ var init_client = __esm({
2472
2582
  init_utils();
2473
2583
  DEFAULT_SIGLUME_API_BASE = "https://siglume.com/v1";
2474
2584
  RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
2585
+ MINIMUM_JPY_OPERATION_PRICE_CURRENCIES = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
2475
2586
  CursorPageResult = class {
2476
2587
  items;
2477
2588
  next_cursor;
@@ -2579,6 +2690,7 @@ var init_client = __esm({
2579
2690
  "jurisdiction",
2580
2691
  "price_model",
2581
2692
  "price_value_minor",
2693
+ "pricing_plan",
2582
2694
  "currency",
2583
2695
  "allow_free_trial",
2584
2696
  "free_trial_duration_days",
@@ -2595,6 +2707,9 @@ var init_client = __esm({
2595
2707
  payload[fieldName] = value;
2596
2708
  }
2597
2709
  }
2710
+ if (payload.pricing_plan !== void 0 && (typeof payload.pricing_plan !== "object" || Array.isArray(payload.pricing_plan))) {
2711
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
2712
+ }
2598
2713
  if (payload.store_vertical === void 0 || payload.store_vertical === null) {
2599
2714
  throw new SiglumeClientError(
2600
2715
  "AppManifest.store_vertical is required. Choose 'api' for normal API Store listings or 'game' for API games."
@@ -2610,6 +2725,13 @@ var init_client = __esm({
2610
2725
  throw new SiglumeClientError(`AppManifest.currency must be 'USD' or 'JPY'. Got ${String(payload.currency)}.`);
2611
2726
  }
2612
2727
  payload.currency = currency;
2728
+ if (payload.pricing_plan !== void 0) {
2729
+ validatePricingPlanFloor(payload.pricing_plan, currency);
2730
+ }
2731
+ const priceModel = String(payload.price_model ?? "free").trim().toLowerCase();
2732
+ if ((priceModel === "usage_based" || priceModel === "per_action") && !pricingPlanHasItems(payload.pricing_plan)) {
2733
+ throw new SiglumeClientError("AppManifest.pricing_plan.items is required for usage_based/per_action pricing.");
2734
+ }
2613
2735
  if (payload.allow_free_trial === void 0 || payload.allow_free_trial === null) {
2614
2736
  throw new SiglumeClientError(
2615
2737
  "AppManifest.allow_free_trial is required. Pass true to offer a Plus/Pro buyer free trial or false to disable trials."
@@ -5284,53 +5406,8 @@ function stableValue(value) {
5284
5406
  return value;
5285
5407
  }
5286
5408
 
5287
- // src/types.ts
5288
- var PermissionClass = {
5289
- READ_ONLY: "read-only",
5290
- ACTION: "action",
5291
- PAYMENT: "payment",
5292
- /** @deprecated Use READ_ONLY. Behaves identically. */
5293
- RECOMMENDATION: "recommendation"
5294
- };
5295
- var ApprovalMode = {
5296
- AUTO: "auto",
5297
- BUDGET_BOUNDED: "budget-bounded",
5298
- ALWAYS_ASK: "always-ask",
5299
- DENY: "deny"
5300
- };
5301
- var Environment = {
5302
- SANDBOX: "sandbox",
5303
- LIVE: "live"
5304
- };
5305
- var PriceModel = {
5306
- FREE: "free",
5307
- SUBSCRIPTION: "subscription",
5308
- ONE_TIME: "one_time",
5309
- BUNDLE: "bundle",
5310
- USAGE_BASED: "usage_based",
5311
- PER_ACTION: "per_action"
5312
- };
5313
- var AppCategory = {
5314
- COMMERCE: "commerce",
5315
- BOOKING: "booking",
5316
- CRM: "crm",
5317
- FINANCE: "finance",
5318
- DOCUMENT: "document",
5319
- COMMUNICATION: "communication",
5320
- MONITORING: "monitoring",
5321
- OTHER: "other"
5322
- };
5323
- var ToolManualPermissionClass = {
5324
- READ_ONLY: "read_only",
5325
- ACTION: "action",
5326
- PAYMENT: "payment"
5327
- };
5328
- var SettlementMode = {
5329
- STRIPE_CHECKOUT: "stripe_checkout",
5330
- STRIPE_PAYMENT_INTENT: "stripe_payment_intent",
5331
- POLYGON_MANDATE: "polygon_mandate",
5332
- EMBEDDED_WALLET_CHARGE: "embedded_wallet_charge"
5333
- };
5409
+ // src/runtime.ts
5410
+ init_types();
5334
5411
 
5335
5412
  // src/testing/recorder.ts
5336
5413
  var CASSETTE_VERSION = 1;
@@ -5722,6 +5799,7 @@ Actual: ${requestSignature(requestRecord, ignoreBodyFields)}`
5722
5799
  };
5723
5800
 
5724
5801
  // src/tool-manual-validator.ts
5802
+ init_types();
5725
5803
  init_utils();
5726
5804
  var JURISDICTION_PATTERN = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/;
5727
5805
  var TOOL_NAME_RE = /^[A-Za-z0-9_]{3,64}$/;
@@ -5993,6 +6071,64 @@ function validate_tool_manual(manualInput) {
5993
6071
  // src/runtime.ts
5994
6072
  init_web3();
5995
6073
  var CAPABILITY_KEY_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
6074
+ var MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2 = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
6075
+ function pricingPlanFloorIssues(plan, defaultCurrency) {
6076
+ const issues = [];
6077
+ if (plan === void 0 || plan === null) {
6078
+ return issues;
6079
+ }
6080
+ if (typeof plan !== "object" || Array.isArray(plan)) {
6081
+ return ["pricing_plan must be an object when provided"];
6082
+ }
6083
+ const record = plan;
6084
+ const items = record.items;
6085
+ if (items === void 0 || items === null) {
6086
+ return issues;
6087
+ }
6088
+ if (!Array.isArray(items)) {
6089
+ return ["pricing_plan.items must be an array when provided"];
6090
+ }
6091
+ const planCurrency = String(record.currency ?? defaultCurrency ?? "").trim().toUpperCase();
6092
+ const seenKeys = /* @__PURE__ */ new Set();
6093
+ items.forEach((item, index) => {
6094
+ if (typeof item !== "object" || item === null || Array.isArray(item)) {
6095
+ issues.push(`pricing_plan.items[${index}] must be an object`);
6096
+ return;
6097
+ }
6098
+ const itemRecord = item;
6099
+ const itemKey = String(
6100
+ itemRecord.key ?? itemRecord.operation ?? itemRecord.operation_key ?? itemRecord.request_type ?? itemRecord.receipt_code ?? itemRecord.action ?? ""
6101
+ ).trim();
6102
+ if (!itemKey) {
6103
+ issues.push(`pricing_plan.items[${index}].key is required`);
6104
+ } else if (seenKeys.has(itemKey)) {
6105
+ issues.push(`pricing_plan.items[${index}].key duplicates ${itemKey}`);
6106
+ } else {
6107
+ seenKeys.add(itemKey);
6108
+ }
6109
+ const amountRaw = itemRecord.price_minor ?? itemRecord.amount_minor ?? itemRecord.cost_minor ?? itemRecord.value_minor;
6110
+ if (amountRaw === void 0 || amountRaw === null) {
6111
+ issues.push(`pricing_plan.items[${index}].price_minor is required`);
6112
+ return;
6113
+ }
6114
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
6115
+ if (!Number.isInteger(amountMinor)) {
6116
+ issues.push(`pricing_plan.items[${index}].price_minor must be an integer`);
6117
+ return;
6118
+ }
6119
+ if (amountMinor < 0) {
6120
+ issues.push(`pricing_plan.items[${index}].price_minor must be zero or positive`);
6121
+ return;
6122
+ }
6123
+ const currency = String(itemRecord.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
6124
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
6125
+ issues.push(
6126
+ `pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing`
6127
+ );
6128
+ }
6129
+ });
6130
+ return issues;
6131
+ }
5996
6132
  function normalizeExecutionResult(result, executionKind) {
5997
6133
  return {
5998
6134
  success: Boolean(result.success),
@@ -6080,6 +6216,10 @@ var AppTestHarness = class {
6080
6216
  if (!manifest.example_prompts || manifest.example_prompts.length === 0) {
6081
6217
  issues.push("at least one example_prompt is recommended");
6082
6218
  }
6219
+ issues.push(...pricingPlanFloorIssues(manifest.pricing_plan, String(manifest.currency ?? "USD")));
6220
+ 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)) {
6221
+ issues.push("pricing_plan.items is required for usage_based/per_action pricing");
6222
+ }
6083
6223
  if (manifest.permission_class === PermissionClass.ACTION || manifest.permission_class === PermissionClass.PAYMENT) {
6084
6224
  if (!manifest.dry_run_supported) {
6085
6225
  issues.push("action/payment apps should support dry_run");
@@ -6155,7 +6295,7 @@ var AppTestHarness = class {
6155
6295
  };
6156
6296
  }
6157
6297
  return {
6158
- experimental: manifest.price_model === PriceModel.USAGE_BASED || manifest.price_model === PriceModel.PER_ACTION,
6298
+ experimental: false,
6159
6299
  usage_record,
6160
6300
  invoice_line_preview
6161
6301
  };