@siglume/api-sdk 1.0.0 → 1.2.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.
@@ -123,6 +123,7 @@ declare const PriceModel: {
123
123
  readonly PER_ACTION: "per_action";
124
124
  };
125
125
  type PriceModel = (typeof PriceModel)[keyof typeof PriceModel];
126
+ type BillingTiming = "post" | "prepay";
126
127
  declare const AppCategory: {
127
128
  readonly COMMERCE: "commerce";
128
129
  readonly BOOKING: "booking";
@@ -178,6 +179,8 @@ interface AppManifest {
178
179
  permission_scopes?: string[];
179
180
  price_model?: PriceModel;
180
181
  price_value_minor?: number;
182
+ pricing_plan?: PricingPlan;
183
+ billing_timing?: BillingTiming;
181
184
  currency: ListingCurrency;
182
185
  allow_free_trial: boolean;
183
186
  free_trial_duration_days?: number;
@@ -261,6 +264,28 @@ interface EnvelopeMeta {
261
264
  request_id?: string | null;
262
265
  trace_id?: string | null;
263
266
  }
267
+ interface PricingPlanItem {
268
+ key?: string | null;
269
+ label?: string | null;
270
+ price_minor?: number | null;
271
+ amount_minor?: number | null;
272
+ currency?: string | null;
273
+ unit_label?: string | null;
274
+ description?: string | null;
275
+ conditions?: unknown;
276
+ receipt_code?: string | null;
277
+ }
278
+ interface PricingPlan {
279
+ billing_model?: string | null;
280
+ display_name?: string | null;
281
+ summary?: string | null;
282
+ description?: string | null;
283
+ currency?: string | null;
284
+ unit_label?: string | null;
285
+ free_upfront_invocation?: boolean | null;
286
+ fallback_note?: string | null;
287
+ items?: PricingPlanItem[];
288
+ }
264
289
  interface CursorPage<T> {
265
290
  items: T[];
266
291
  next_cursor?: string | null;
@@ -282,6 +307,8 @@ interface AppListingRecord {
282
307
  dry_run_supported: boolean;
283
308
  price_model?: string | null;
284
309
  price_value_minor: number;
310
+ pricing_plan?: PricingPlan | null;
311
+ billing_timing?: BillingTiming | string | null;
285
312
  currency: string;
286
313
  allow_free_trial: boolean;
287
314
  free_trial_duration_days: number;
@@ -123,6 +123,7 @@ declare const PriceModel: {
123
123
  readonly PER_ACTION: "per_action";
124
124
  };
125
125
  type PriceModel = (typeof PriceModel)[keyof typeof PriceModel];
126
+ type BillingTiming = "post" | "prepay";
126
127
  declare const AppCategory: {
127
128
  readonly COMMERCE: "commerce";
128
129
  readonly BOOKING: "booking";
@@ -178,6 +179,8 @@ interface AppManifest {
178
179
  permission_scopes?: string[];
179
180
  price_model?: PriceModel;
180
181
  price_value_minor?: number;
182
+ pricing_plan?: PricingPlan;
183
+ billing_timing?: BillingTiming;
181
184
  currency: ListingCurrency;
182
185
  allow_free_trial: boolean;
183
186
  free_trial_duration_days?: number;
@@ -261,6 +264,28 @@ interface EnvelopeMeta {
261
264
  request_id?: string | null;
262
265
  trace_id?: string | null;
263
266
  }
267
+ interface PricingPlanItem {
268
+ key?: string | null;
269
+ label?: string | null;
270
+ price_minor?: number | null;
271
+ amount_minor?: number | null;
272
+ currency?: string | null;
273
+ unit_label?: string | null;
274
+ description?: string | null;
275
+ conditions?: unknown;
276
+ receipt_code?: string | null;
277
+ }
278
+ interface PricingPlan {
279
+ billing_model?: string | null;
280
+ display_name?: string | null;
281
+ summary?: string | null;
282
+ description?: string | null;
283
+ currency?: string | null;
284
+ unit_label?: string | null;
285
+ free_upfront_invocation?: boolean | null;
286
+ fallback_note?: string | null;
287
+ items?: PricingPlanItem[];
288
+ }
264
289
  interface CursorPage<T> {
265
290
  items: T[];
266
291
  next_cursor?: string | null;
@@ -282,6 +307,8 @@ interface AppListingRecord {
282
307
  dry_run_supported: boolean;
283
308
  price_model?: string | null;
284
309
  price_value_minor: number;
310
+ pricing_plan?: PricingPlan | null;
311
+ billing_timing?: BillingTiming | string | null;
285
312
  currency: string;
286
313
  allow_free_trial: boolean;
287
314
  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,8 @@ 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,
1476
+ billing_timing: String(data.billing_timing ?? metadata.billing_timing ?? "post"),
1367
1477
  currency: String(data.currency ?? "USD"),
1368
1478
  allow_free_trial: Boolean(data.allow_free_trial ?? false),
1369
1479
  free_trial_duration_days: Number(data.free_trial_duration_days ?? 30),
@@ -2461,10 +2571,11 @@ function cloneJsonLike(value) {
2461
2571
  }
2462
2572
  return value;
2463
2573
  }
2464
- var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, CursorPageResult, SiglumeClient;
2574
+ var DEFAULT_SIGLUME_API_BASE, RETRYABLE_STATUS_CODES, MINIMUM_JPY_OPERATION_PRICE_CURRENCIES, CursorPageResult, SiglumeClient;
2465
2575
  var init_client = __esm({
2466
2576
  "src/client.ts"() {
2467
2577
  "use strict";
2578
+ init_types();
2468
2579
  init_errors();
2469
2580
  init_webhooks();
2470
2581
  init_web3();
@@ -2472,6 +2583,7 @@ var init_client = __esm({
2472
2583
  init_utils();
2473
2584
  DEFAULT_SIGLUME_API_BASE = "https://siglume.com/v1";
2474
2585
  RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
2586
+ MINIMUM_JPY_OPERATION_PRICE_CURRENCIES = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
2475
2587
  CursorPageResult = class {
2476
2588
  items;
2477
2589
  next_cursor;
@@ -2579,6 +2691,8 @@ var init_client = __esm({
2579
2691
  "jurisdiction",
2580
2692
  "price_model",
2581
2693
  "price_value_minor",
2694
+ "pricing_plan",
2695
+ "billing_timing",
2582
2696
  "currency",
2583
2697
  "allow_free_trial",
2584
2698
  "free_trial_duration_days",
@@ -2595,6 +2709,16 @@ var init_client = __esm({
2595
2709
  payload[fieldName] = value;
2596
2710
  }
2597
2711
  }
2712
+ if (payload.pricing_plan !== void 0 && (typeof payload.pricing_plan !== "object" || Array.isArray(payload.pricing_plan))) {
2713
+ throw new SiglumeClientError("AppManifest.pricing_plan must be an object when provided.");
2714
+ }
2715
+ if (payload.billing_timing !== void 0 && payload.billing_timing !== null) {
2716
+ const billingTiming = String(payload.billing_timing || "post").trim().toLowerCase();
2717
+ if (billingTiming !== "post" && billingTiming !== "prepay") {
2718
+ throw new SiglumeClientError("AppManifest.billing_timing must be 'post' or 'prepay'.");
2719
+ }
2720
+ payload.billing_timing = billingTiming;
2721
+ }
2598
2722
  if (payload.store_vertical === void 0 || payload.store_vertical === null) {
2599
2723
  throw new SiglumeClientError(
2600
2724
  "AppManifest.store_vertical is required. Choose 'api' for normal API Store listings or 'game' for API games."
@@ -2610,6 +2734,13 @@ var init_client = __esm({
2610
2734
  throw new SiglumeClientError(`AppManifest.currency must be 'USD' or 'JPY'. Got ${String(payload.currency)}.`);
2611
2735
  }
2612
2736
  payload.currency = currency;
2737
+ if (payload.pricing_plan !== void 0) {
2738
+ validatePricingPlanFloor(payload.pricing_plan, currency);
2739
+ }
2740
+ const priceModel = String(payload.price_model ?? "free").trim().toLowerCase();
2741
+ if ((priceModel === "usage_based" || priceModel === "per_action") && !pricingPlanHasItems(payload.pricing_plan)) {
2742
+ throw new SiglumeClientError("AppManifest.pricing_plan.items is required for usage_based/per_action pricing.");
2743
+ }
2613
2744
  if (payload.allow_free_trial === void 0 || payload.allow_free_trial === null) {
2614
2745
  throw new SiglumeClientError(
2615
2746
  "AppManifest.allow_free_trial is required. Pass true to offer a Plus/Pro buyer free trial or false to disable trials."
@@ -5284,53 +5415,8 @@ function stableValue(value) {
5284
5415
  return value;
5285
5416
  }
5286
5417
 
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
- };
5418
+ // src/runtime.ts
5419
+ init_types();
5334
5420
 
5335
5421
  // src/testing/recorder.ts
5336
5422
  var CASSETTE_VERSION = 1;
@@ -5722,6 +5808,7 @@ Actual: ${requestSignature(requestRecord, ignoreBodyFields)}`
5722
5808
  };
5723
5809
 
5724
5810
  // src/tool-manual-validator.ts
5811
+ init_types();
5725
5812
  init_utils();
5726
5813
  var JURISDICTION_PATTERN = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/;
5727
5814
  var TOOL_NAME_RE = /^[A-Za-z0-9_]{3,64}$/;
@@ -5993,6 +6080,64 @@ function validate_tool_manual(manualInput) {
5993
6080
  // src/runtime.ts
5994
6081
  init_web3();
5995
6082
  var CAPABILITY_KEY_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
6083
+ var MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2 = /* @__PURE__ */ new Set(["JPY", "JPYC"]);
6084
+ function pricingPlanFloorIssues(plan, defaultCurrency) {
6085
+ const issues = [];
6086
+ if (plan === void 0 || plan === null) {
6087
+ return issues;
6088
+ }
6089
+ if (typeof plan !== "object" || Array.isArray(plan)) {
6090
+ return ["pricing_plan must be an object when provided"];
6091
+ }
6092
+ const record = plan;
6093
+ const items = record.items;
6094
+ if (items === void 0 || items === null) {
6095
+ return issues;
6096
+ }
6097
+ if (!Array.isArray(items)) {
6098
+ return ["pricing_plan.items must be an array when provided"];
6099
+ }
6100
+ const planCurrency = String(record.currency ?? defaultCurrency ?? "").trim().toUpperCase();
6101
+ const seenKeys = /* @__PURE__ */ new Set();
6102
+ items.forEach((item, index) => {
6103
+ if (typeof item !== "object" || item === null || Array.isArray(item)) {
6104
+ issues.push(`pricing_plan.items[${index}] must be an object`);
6105
+ return;
6106
+ }
6107
+ const itemRecord = item;
6108
+ const itemKey = String(
6109
+ itemRecord.key ?? itemRecord.operation ?? itemRecord.operation_key ?? itemRecord.request_type ?? itemRecord.receipt_code ?? itemRecord.action ?? ""
6110
+ ).trim();
6111
+ if (!itemKey) {
6112
+ issues.push(`pricing_plan.items[${index}].key is required`);
6113
+ } else if (seenKeys.has(itemKey)) {
6114
+ issues.push(`pricing_plan.items[${index}].key duplicates ${itemKey}`);
6115
+ } else {
6116
+ seenKeys.add(itemKey);
6117
+ }
6118
+ const amountRaw = itemRecord.price_minor ?? itemRecord.amount_minor ?? itemRecord.cost_minor ?? itemRecord.value_minor;
6119
+ if (amountRaw === void 0 || amountRaw === null) {
6120
+ issues.push(`pricing_plan.items[${index}].price_minor is required`);
6121
+ return;
6122
+ }
6123
+ const amountMinor = typeof amountRaw === "number" ? amountRaw : typeof amountRaw === "string" && amountRaw.trim() ? Number(amountRaw) : NaN;
6124
+ if (!Number.isInteger(amountMinor)) {
6125
+ issues.push(`pricing_plan.items[${index}].price_minor must be an integer`);
6126
+ return;
6127
+ }
6128
+ if (amountMinor < 0) {
6129
+ issues.push(`pricing_plan.items[${index}].price_minor must be zero or positive`);
6130
+ return;
6131
+ }
6132
+ const currency = String(itemRecord.currency ?? planCurrency ?? defaultCurrency ?? "").trim().toUpperCase();
6133
+ if (MINIMUM_JPY_OPERATION_PRICE_CURRENCIES2.has(currency) && amountMinor > 0 && amountMinor < MINIMUM_JPY_OPERATION_PRICE_MINOR) {
6134
+ issues.push(
6135
+ `pricing_plan.items[${index}].price_minor must be 0 or at least ${MINIMUM_JPY_OPERATION_PRICE_MINOR} for JPY/JPYC operation billing`
6136
+ );
6137
+ }
6138
+ });
6139
+ return issues;
6140
+ }
5996
6141
  function normalizeExecutionResult(result, executionKind) {
5997
6142
  return {
5998
6143
  success: Boolean(result.success),
@@ -6080,6 +6225,13 @@ var AppTestHarness = class {
6080
6225
  if (!manifest.example_prompts || manifest.example_prompts.length === 0) {
6081
6226
  issues.push("at least one example_prompt is recommended");
6082
6227
  }
6228
+ issues.push(...pricingPlanFloorIssues(manifest.pricing_plan, String(manifest.currency ?? "USD")));
6229
+ if (manifest.billing_timing !== void 0 && manifest.billing_timing !== "post" && manifest.billing_timing !== "prepay") {
6230
+ issues.push("billing_timing must be 'post' or 'prepay'");
6231
+ }
6232
+ 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)) {
6233
+ issues.push("pricing_plan.items is required for usage_based/per_action pricing");
6234
+ }
6083
6235
  if (manifest.permission_class === PermissionClass.ACTION || manifest.permission_class === PermissionClass.PAYMENT) {
6084
6236
  if (!manifest.dry_run_supported) {
6085
6237
  issues.push("action/payment apps should support dry_run");
@@ -6155,7 +6307,7 @@ var AppTestHarness = class {
6155
6307
  };
6156
6308
  }
6157
6309
  return {
6158
- experimental: manifest.price_model === PriceModel.USAGE_BASED || manifest.price_model === PriceModel.PER_ACTION,
6310
+ experimental: false,
6159
6311
  usage_record,
6160
6312
  invoice_line_preview
6161
6313
  };