@yawlabs/lemonsqueezy-mcp 0.10.0 → 0.10.1

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.
Files changed (2) hide show
  1. package/dist/index.js +185 -181
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -30200,6 +30200,189 @@ var StdioServerTransport = class {
30200
30200
  }
30201
30201
  };
30202
30202
 
30203
+ // src/guardrails.ts
30204
+ var GuardrailError = class extends Error {
30205
+ constructor(message) {
30206
+ super(message);
30207
+ this.name = "GuardrailError";
30208
+ }
30209
+ };
30210
+ var AUTHORITY_CLASSES = ["read", "pii", "mutate", "money", "recurring", "key", "webhook"];
30211
+ function isAuthorityClass(s) {
30212
+ return AUTHORITY_CLASSES.includes(s);
30213
+ }
30214
+ var cachedOptions = null;
30215
+ var destructiveTimestamps = [];
30216
+ var classTimestamps = /* @__PURE__ */ new Map();
30217
+ function readNumber(name, raw) {
30218
+ if (raw === void 0 || raw.trim() === "") return null;
30219
+ const n = Number(raw);
30220
+ if (!Number.isFinite(n) || n < 0) {
30221
+ throw new Error(`${name} must be a non-negative number (got ${JSON.stringify(raw)})`);
30222
+ }
30223
+ return n;
30224
+ }
30225
+ function parseDisabledClasses(raw) {
30226
+ if (!raw || raw.trim() === "") return null;
30227
+ const out = /* @__PURE__ */ new Set();
30228
+ for (const part of raw.split(",")) {
30229
+ const cls = part.trim();
30230
+ if (!cls) continue;
30231
+ if (!isAuthorityClass(cls)) {
30232
+ throw new Error(
30233
+ `LEMONSQUEEZY_DISABLE_CLASSES contains unknown class ${JSON.stringify(cls)} (expected one of: ${AUTHORITY_CLASSES.join(", ")})`
30234
+ );
30235
+ }
30236
+ out.add(cls);
30237
+ }
30238
+ return out.size > 0 ? out : null;
30239
+ }
30240
+ function parseClassRateLimits(raw) {
30241
+ if (!raw || raw.trim() === "") return null;
30242
+ const out = /* @__PURE__ */ new Map();
30243
+ for (const part of raw.split(",")) {
30244
+ const segment = part.trim();
30245
+ if (!segment) continue;
30246
+ const colon = segment.indexOf(":");
30247
+ if (colon < 0) {
30248
+ throw new Error(
30249
+ `LEMONSQUEEZY_RATE_LIMIT_PER_CLASS entry missing colon: ${JSON.stringify(segment)} (expected class:N or class:N/h)`
30250
+ );
30251
+ }
30252
+ const cls = segment.slice(0, colon).trim();
30253
+ if (!isAuthorityClass(cls)) {
30254
+ throw new Error(
30255
+ `LEMONSQUEEZY_RATE_LIMIT_PER_CLASS contains unknown class ${JSON.stringify(cls)} (expected one of: ${AUTHORITY_CLASSES.join(", ")})`
30256
+ );
30257
+ }
30258
+ const specRaw = segment.slice(colon + 1).trim();
30259
+ const slash = specRaw.indexOf("/");
30260
+ const numPart = slash >= 0 ? specRaw.slice(0, slash).trim() : specRaw;
30261
+ const unitPart = slash >= 0 ? specRaw.slice(slash + 1).trim().toLowerCase() : "m";
30262
+ const n = Number(numPart);
30263
+ if (!Number.isFinite(n) || n < 0 || numPart === "") {
30264
+ throw new Error(`LEMONSQUEEZY_RATE_LIMIT_PER_CLASS entry has invalid number: ${JSON.stringify(segment)}`);
30265
+ }
30266
+ let windowMs;
30267
+ if (unitPart === "m") windowMs = 6e4;
30268
+ else if (unitPart === "h") windowMs = 36e5;
30269
+ else {
30270
+ throw new Error(
30271
+ `LEMONSQUEEZY_RATE_LIMIT_PER_CLASS entry has invalid unit (expected m or h): ${JSON.stringify(segment)}`
30272
+ );
30273
+ }
30274
+ out.set(cls, { limit: n, windowMs });
30275
+ }
30276
+ return out.size > 0 ? out : null;
30277
+ }
30278
+ function loadOptions() {
30279
+ if (cachedOptions) return cachedOptions;
30280
+ const allowed = process.env.LEMONSQUEEZY_ALLOWED_STORE_IDS;
30281
+ const allowedSet = allowed ? new Set(
30282
+ allowed.split(",").map((s) => s.trim()).filter(Boolean)
30283
+ ) : null;
30284
+ cachedOptions = {
30285
+ allowedStoreIds: allowedSet && allowedSet.size > 0 ? allowedSet : null,
30286
+ maxRefundAmountCents: readNumber(
30287
+ "LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS",
30288
+ process.env.LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS
30289
+ ),
30290
+ rateLimitPerMinute: readNumber(
30291
+ "LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT",
30292
+ process.env.LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT
30293
+ ),
30294
+ disabledClasses: parseDisabledClasses(process.env.LEMONSQUEEZY_DISABLE_CLASSES),
30295
+ classRateLimits: parseClassRateLimits(process.env.LEMONSQUEEZY_RATE_LIMIT_PER_CLASS)
30296
+ };
30297
+ return cachedOptions;
30298
+ }
30299
+ function checkStoreAllowed(storeId) {
30300
+ if (!storeId) return;
30301
+ const o = loadOptions();
30302
+ if (!o.allowedStoreIds) return;
30303
+ if (!o.allowedStoreIds.has(String(storeId))) {
30304
+ throw new GuardrailError(`Store ID ${storeId} is not in LEMONSQUEEZY_ALLOWED_STORE_IDS allowlist`);
30305
+ }
30306
+ }
30307
+ function checkRefundAmount(cents) {
30308
+ const o = loadOptions();
30309
+ if (o.maxRefundAmountCents === null) return;
30310
+ if (cents > o.maxRefundAmountCents) {
30311
+ throw new GuardrailError(
30312
+ `Refund amount ${cents} cents exceeds LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS (${o.maxRefundAmountCents})`
30313
+ );
30314
+ }
30315
+ }
30316
+ function checkDestructiveRateLimit(now = Date.now()) {
30317
+ const o = loadOptions();
30318
+ if (o.rateLimitPerMinute === null) return;
30319
+ const cutoff = now - 6e4;
30320
+ destructiveTimestamps = destructiveTimestamps.filter((t) => t > cutoff);
30321
+ if (destructiveTimestamps.length >= o.rateLimitPerMinute) {
30322
+ throw new GuardrailError(`Destructive call rate limit exceeded (${o.rateLimitPerMinute}/min). Wait and retry.`);
30323
+ }
30324
+ destructiveTimestamps.push(now);
30325
+ }
30326
+ function isStoreAllowlistActive() {
30327
+ return loadOptions().allowedStoreIds !== null;
30328
+ }
30329
+ function loadGuardrailOptions() {
30330
+ loadOptions();
30331
+ }
30332
+ function isPresent(value) {
30333
+ if (value === void 0 || value === null) return false;
30334
+ if (typeof value === "string" && value === "") return false;
30335
+ if (Array.isArray(value) && value.length === 0) return false;
30336
+ return true;
30337
+ }
30338
+ function checkStoreScopedToolInput(tool, input) {
30339
+ const toolAcceptsStoreId = "storeId" in tool.inputSchema.shape;
30340
+ if (toolAcceptsStoreId) {
30341
+ const raw = input.storeId;
30342
+ if (raw !== void 0 && raw !== null && raw !== "") {
30343
+ checkStoreAllowed(String(raw));
30344
+ } else if (isStoreAllowlistActive()) {
30345
+ throw new GuardrailError("storeId is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set");
30346
+ }
30347
+ }
30348
+ if (tool.requiredFilters && tool.requiredFilters.length > 0 && isStoreAllowlistActive()) {
30349
+ const anyPresent = tool.requiredFilters.some((key) => isPresent(input[key]));
30350
+ if (!anyPresent) {
30351
+ throw new GuardrailError(
30352
+ `At least one of [${tool.requiredFilters.join(", ")}] is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set`
30353
+ );
30354
+ }
30355
+ }
30356
+ }
30357
+ function isDestructiveCall(tool, input) {
30358
+ if (typeof tool.isDestructive === "function") return tool.isDestructive(input);
30359
+ return tool.annotations?.destructiveHint === true;
30360
+ }
30361
+ function checkClassAllowed(cls) {
30362
+ const o = loadOptions();
30363
+ if (!o.disabledClasses) return;
30364
+ if (o.disabledClasses.has(cls)) {
30365
+ throw new GuardrailError(`Tool authority class ${JSON.stringify(cls)} is disabled by LEMONSQUEEZY_DISABLE_CLASSES`);
30366
+ }
30367
+ }
30368
+ function checkClassRateLimit(cls, now = Date.now()) {
30369
+ const o = loadOptions();
30370
+ if (!o.classRateLimits) return;
30371
+ const spec = o.classRateLimits.get(cls);
30372
+ if (!spec) return;
30373
+ const cutoff = now - spec.windowMs;
30374
+ const list = (classTimestamps.get(cls) ?? []).filter((t) => t > cutoff);
30375
+ if (list.length >= spec.limit) {
30376
+ const unit = spec.windowMs === 6e4 ? "min" : spec.windowMs === 36e5 ? "hour" : `${spec.windowMs}ms`;
30377
+ classTimestamps.set(cls, list);
30378
+ throw new GuardrailError(
30379
+ `Class ${JSON.stringify(cls)} rate limit exceeded (${spec.limit}/${unit}). Wait and retry.`
30380
+ );
30381
+ }
30382
+ list.push(now);
30383
+ classTimestamps.set(cls, list);
30384
+ }
30385
+
30203
30386
  // src/logger.ts
30204
30387
  function getLogLevel() {
30205
30388
  const v = process.env.LEMONSQUEEZY_LOG;
@@ -31461,186 +31644,6 @@ var orderItemTools = [
31461
31644
  }
31462
31645
  ];
31463
31646
 
31464
- // src/guardrails.ts
31465
- var GuardrailError = class extends Error {
31466
- constructor(message) {
31467
- super(message);
31468
- this.name = "GuardrailError";
31469
- }
31470
- };
31471
- var AUTHORITY_CLASSES = ["read", "pii", "mutate", "money", "recurring", "key", "webhook"];
31472
- function isAuthorityClass(s) {
31473
- return AUTHORITY_CLASSES.includes(s);
31474
- }
31475
- var cachedOptions = null;
31476
- var destructiveTimestamps = [];
31477
- var classTimestamps = /* @__PURE__ */ new Map();
31478
- function readNumber(name, raw) {
31479
- if (raw === void 0 || raw.trim() === "") return null;
31480
- const n = Number(raw);
31481
- if (!Number.isFinite(n) || n < 0) {
31482
- throw new Error(`${name} must be a non-negative number (got ${JSON.stringify(raw)})`);
31483
- }
31484
- return n;
31485
- }
31486
- function parseDisabledClasses(raw) {
31487
- if (!raw || raw.trim() === "") return null;
31488
- const out = /* @__PURE__ */ new Set();
31489
- for (const part of raw.split(",")) {
31490
- const cls = part.trim();
31491
- if (!cls) continue;
31492
- if (!isAuthorityClass(cls)) {
31493
- throw new Error(
31494
- `LEMONSQUEEZY_DISABLE_CLASSES contains unknown class ${JSON.stringify(cls)} (expected one of: ${AUTHORITY_CLASSES.join(", ")})`
31495
- );
31496
- }
31497
- out.add(cls);
31498
- }
31499
- return out.size > 0 ? out : null;
31500
- }
31501
- function parseClassRateLimits(raw) {
31502
- if (!raw || raw.trim() === "") return null;
31503
- const out = /* @__PURE__ */ new Map();
31504
- for (const part of raw.split(",")) {
31505
- const segment = part.trim();
31506
- if (!segment) continue;
31507
- const colon = segment.indexOf(":");
31508
- if (colon < 0) {
31509
- throw new Error(
31510
- `LEMONSQUEEZY_RATE_LIMIT_PER_CLASS entry missing colon: ${JSON.stringify(segment)} (expected class:N or class:N/h)`
31511
- );
31512
- }
31513
- const cls = segment.slice(0, colon).trim();
31514
- if (!isAuthorityClass(cls)) {
31515
- throw new Error(
31516
- `LEMONSQUEEZY_RATE_LIMIT_PER_CLASS contains unknown class ${JSON.stringify(cls)} (expected one of: ${AUTHORITY_CLASSES.join(", ")})`
31517
- );
31518
- }
31519
- const specRaw = segment.slice(colon + 1).trim();
31520
- const slash = specRaw.indexOf("/");
31521
- const numPart = slash >= 0 ? specRaw.slice(0, slash).trim() : specRaw;
31522
- const unitPart = slash >= 0 ? specRaw.slice(slash + 1).trim().toLowerCase() : "m";
31523
- const n = Number(numPart);
31524
- if (!Number.isFinite(n) || n < 0 || numPart === "") {
31525
- throw new Error(`LEMONSQUEEZY_RATE_LIMIT_PER_CLASS entry has invalid number: ${JSON.stringify(segment)}`);
31526
- }
31527
- let windowMs;
31528
- if (unitPart === "m") windowMs = 6e4;
31529
- else if (unitPart === "h") windowMs = 36e5;
31530
- else {
31531
- throw new Error(
31532
- `LEMONSQUEEZY_RATE_LIMIT_PER_CLASS entry has invalid unit (expected m or h): ${JSON.stringify(segment)}`
31533
- );
31534
- }
31535
- out.set(cls, { limit: n, windowMs });
31536
- }
31537
- return out.size > 0 ? out : null;
31538
- }
31539
- function loadOptions() {
31540
- if (cachedOptions) return cachedOptions;
31541
- const allowed = process.env.LEMONSQUEEZY_ALLOWED_STORE_IDS;
31542
- const allowedSet = allowed ? new Set(
31543
- allowed.split(",").map((s) => s.trim()).filter(Boolean)
31544
- ) : null;
31545
- cachedOptions = {
31546
- allowedStoreIds: allowedSet && allowedSet.size > 0 ? allowedSet : null,
31547
- maxRefundAmountCents: readNumber(
31548
- "LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS",
31549
- process.env.LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS
31550
- ),
31551
- rateLimitPerMinute: readNumber(
31552
- "LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT",
31553
- process.env.LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT
31554
- ),
31555
- disabledClasses: parseDisabledClasses(process.env.LEMONSQUEEZY_DISABLE_CLASSES),
31556
- classRateLimits: parseClassRateLimits(process.env.LEMONSQUEEZY_RATE_LIMIT_PER_CLASS)
31557
- };
31558
- return cachedOptions;
31559
- }
31560
- function checkStoreAllowed(storeId) {
31561
- if (!storeId) return;
31562
- const o = loadOptions();
31563
- if (!o.allowedStoreIds) return;
31564
- if (!o.allowedStoreIds.has(String(storeId))) {
31565
- throw new GuardrailError(`Store ID ${storeId} is not in LEMONSQUEEZY_ALLOWED_STORE_IDS allowlist`);
31566
- }
31567
- }
31568
- function checkRefundAmount(cents) {
31569
- const o = loadOptions();
31570
- if (o.maxRefundAmountCents === null) return;
31571
- if (cents > o.maxRefundAmountCents) {
31572
- throw new GuardrailError(
31573
- `Refund amount ${cents} cents exceeds LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS (${o.maxRefundAmountCents})`
31574
- );
31575
- }
31576
- }
31577
- function checkDestructiveRateLimit(now = Date.now()) {
31578
- const o = loadOptions();
31579
- if (o.rateLimitPerMinute === null) return;
31580
- const cutoff = now - 6e4;
31581
- destructiveTimestamps = destructiveTimestamps.filter((t) => t > cutoff);
31582
- if (destructiveTimestamps.length >= o.rateLimitPerMinute) {
31583
- throw new GuardrailError(`Destructive call rate limit exceeded (${o.rateLimitPerMinute}/min). Wait and retry.`);
31584
- }
31585
- destructiveTimestamps.push(now);
31586
- }
31587
- function isStoreAllowlistActive() {
31588
- return loadOptions().allowedStoreIds !== null;
31589
- }
31590
- function isPresent(value) {
31591
- if (value === void 0 || value === null) return false;
31592
- if (typeof value === "string" && value === "") return false;
31593
- if (Array.isArray(value) && value.length === 0) return false;
31594
- return true;
31595
- }
31596
- function checkStoreScopedToolInput(tool, input) {
31597
- const toolAcceptsStoreId = "storeId" in tool.inputSchema.shape;
31598
- if (toolAcceptsStoreId) {
31599
- const raw = input.storeId;
31600
- if (raw !== void 0 && raw !== null && raw !== "") {
31601
- checkStoreAllowed(String(raw));
31602
- } else if (isStoreAllowlistActive()) {
31603
- throw new GuardrailError("storeId is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set");
31604
- }
31605
- }
31606
- if (tool.requiredFilters && tool.requiredFilters.length > 0 && isStoreAllowlistActive()) {
31607
- const anyPresent = tool.requiredFilters.some((key) => isPresent(input[key]));
31608
- if (!anyPresent) {
31609
- throw new GuardrailError(
31610
- `At least one of [${tool.requiredFilters.join(", ")}] is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set`
31611
- );
31612
- }
31613
- }
31614
- }
31615
- function isDestructiveCall(tool, input) {
31616
- if (typeof tool.isDestructive === "function") return tool.isDestructive(input);
31617
- return tool.annotations?.destructiveHint === true;
31618
- }
31619
- function checkClassAllowed(cls) {
31620
- const o = loadOptions();
31621
- if (!o.disabledClasses) return;
31622
- if (o.disabledClasses.has(cls)) {
31623
- throw new GuardrailError(`Tool authority class ${JSON.stringify(cls)} is disabled by LEMONSQUEEZY_DISABLE_CLASSES`);
31624
- }
31625
- }
31626
- function checkClassRateLimit(cls, now = Date.now()) {
31627
- const o = loadOptions();
31628
- if (!o.classRateLimits) return;
31629
- const spec = o.classRateLimits.get(cls);
31630
- if (!spec) return;
31631
- const cutoff = now - spec.windowMs;
31632
- const list = (classTimestamps.get(cls) ?? []).filter((t) => t > cutoff);
31633
- if (list.length >= spec.limit) {
31634
- const unit = spec.windowMs === 6e4 ? "min" : spec.windowMs === 36e5 ? "hour" : `${spec.windowMs}ms`;
31635
- classTimestamps.set(cls, list);
31636
- throw new GuardrailError(
31637
- `Class ${JSON.stringify(cls)} rate limit exceeded (${spec.limit}/${unit}). Wait and retry.`
31638
- );
31639
- }
31640
- list.push(now);
31641
- classTimestamps.set(cls, list);
31642
- }
31643
-
31644
31647
  // src/tools/orders.ts
31645
31648
  var orderTools = [
31646
31649
  {
@@ -32776,12 +32779,13 @@ function readAuditLogResource(uri) {
32776
32779
  }
32777
32780
 
32778
32781
  // src/index.ts
32779
- var version2 = true ? "0.10.0" : (await null).createRequire(import.meta.url)("../package.json").version;
32782
+ var version2 = true ? "0.10.1" : (await null).createRequire(import.meta.url)("../package.json").version;
32780
32783
  var subcommand = process.argv[2];
32781
32784
  if (subcommand === "version" || subcommand === "--version") {
32782
32785
  console.log(version2);
32783
32786
  process.exit(0);
32784
32787
  }
32788
+ loadGuardrailOptions();
32785
32789
  var allTools = [
32786
32790
  ...userTools,
32787
32791
  ...storeTools,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/lemonsqueezy-mcp",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "mcpName": "io.github.YawLabs/lemonsqueezy-mcp",
5
5
  "description": "LemonSqueezy MCP server for managing your store from AI assistants",
6
6
  "license": "MIT",