@yawlabs/lemonsqueezy-mcp 0.6.2 → 0.7.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.
- package/README.md +7 -7
- package/dist/index.js +275 -122
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -173,11 +173,11 @@ All configuration is via environment variables. Only `LEMONSQUEEZY_API_KEY` (or
|
|
|
173
173
|
| Variable | Purpose |
|
|
174
174
|
| --- | --- |
|
|
175
175
|
| `LEMONSQUEEZY_API_KEY` | LemonSqueezy API token. |
|
|
176
|
-
| `LEMONSQUEEZY_API_KEY_COMMAND` | Command whose stdout produces the API key. Overrides `LEMONSQUEEZY_API_KEY`. Output is cached for 1 hour. Use this to pull short-lived credentials from a vault (`op read`, `gcloud secrets versions access`, etc.) without writing them to env vars. |
|
|
177
|
-
| `LEMONSQUEEZY_ALLOWED_STORE_IDS` | Comma-separated allowlist of store IDs. When set: (1) any tool whose input includes a `storeId` rejects calls to a non-allowed store; (2) tools that *accept* a `storeId` filter (e.g. `ls_list_orders`, `ls_list_subscriptions`) require it — calls without one are blocked so a missing filter cannot return data from every store the API key can see. Tools with no `storeId` field at all (e.g. `ls_refund_order`, `ls_list_stores`) are not gated by this — pair with `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS`
|
|
176
|
+
| `LEMONSQUEEZY_API_KEY_COMMAND` | Command whose stdout produces the API key. Overrides `LEMONSQUEEZY_API_KEY`. Output is cached for 1 hour. Use this to pull short-lived credentials from a vault (`op read`, `gcloud secrets versions access`, etc.) without writing them to env vars. The cache is keyed by the command string, so changing it mid-process refreshes on the next request; it is also invalidated automatically on a 401/403 from the API, so a key rotated upstream takes effect on the next call without waiting for the TTL. |
|
|
177
|
+
| `LEMONSQUEEZY_ALLOWED_STORE_IDS` | Comma-separated allowlist of store IDs. When set: (1) any tool whose input includes a `storeId` rejects calls to a non-allowed store; (2) tools that *accept* a `storeId` filter (e.g. `ls_list_orders`, `ls_list_subscriptions`) require it — calls without one are blocked so a missing filter cannot return data from every store the API key can see. Tools with no `storeId` field at all (e.g. `ls_refund_order`, `ls_cancel_subscription`, `ls_archive_customer`, `ls_delete_webhook`, `ls_delete_discount`, `ls_update_license_key`, `ls_list_stores`) route by their own resource ID and are **not** gated by this allowlist. For those, the only authoritative store boundary is the API key itself — pair this setting with a LemonSqueezy API key scoped to the same store(s), and pair with `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS` / `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` for additional defense in depth. |
|
|
178
178
|
| `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS` | Rejects `ls_refund_order` and `ls_refund_subscription_invoice` calls above this amount. |
|
|
179
|
-
| `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` | Max destructive tool calls per 60-second rolling window. In-process limit — per MCP server instance, not global; each `npx` cold start resets the window. Counts include `ls_update_license_key` calls that set `disabled: true
|
|
180
|
-
| `LEMONSQUEEZY_LOG
|
|
179
|
+
| `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` | Max destructive tool calls per 60-second rolling window. In-process limit — per MCP server instance, not global; each `npx` cold start resets the window. Counts include `ls_update_license_key` calls that set `disabled: true`, and `ls_update_subscription` calls that pause or switch plan. |
|
|
180
|
+
| `LEMONSQUEEZY_LOG` | Structured-log verbosity to stderr. Set to `all` (or legacy `json`) to log every tool and HTTP call, `audit` to log only destructive-call audit entries plus errors (recommended for production), `error` to log only failures. Unset: no logs. Destructive calls are tagged `audit: true` and include their inputs. |
|
|
181
181
|
|
|
182
182
|
### Logging format
|
|
183
183
|
|
|
@@ -191,11 +191,11 @@ HTTP errors include the upstream `X-Request-Id` when present, so support tickets
|
|
|
191
191
|
|
|
192
192
|
For unattended/agentic use against a live store, we recommend:
|
|
193
193
|
|
|
194
|
-
1.
|
|
194
|
+
1. Use a LemonSqueezy API key scoped to the specific store(s) the agent may touch — this is the only authoritative store boundary for tools that route by their own resource ID (refunds, cancels, archive, delete-webhook, etc.). Set `LEMONSQUEEZY_ALLOWED_STORE_IDS` to the same set as a defense-in-depth gate on the tools that *do* take a `storeId`.
|
|
195
195
|
2. Set `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS` to a per-call cap well below any single-refund expectation.
|
|
196
196
|
3. Set `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` to a small number (e.g. 5/min) as a runaway-agent circuit breaker.
|
|
197
|
-
4. Set `LEMONSQUEEZY_LOG=
|
|
198
|
-
5. Run `LEMONSQUEEZY_API_KEY_COMMAND` against a vault-backed secret so credentials can rotate without restarting the server process.
|
|
197
|
+
4. Set `LEMONSQUEEZY_LOG=audit` and ship stderr to your log aggregator. The `audit` level keeps every destructive-call entry plus errors but drops successful reads so log volume stays bounded over weeks of operation. Alert on `status: "guardrail_block"` or elevated error rates per tool. Use `LEMONSQUEEZY_LOG=all` while debugging.
|
|
198
|
+
5. Run `LEMONSQUEEZY_API_KEY_COMMAND` against a vault-backed secret so credentials can rotate without restarting the server process. The API client invalidates its in-process key cache automatically on a 401/403, so a rotated upstream key picks up on the next request rather than waiting on the 1h TTL.
|
|
199
199
|
|
|
200
200
|
What the server does **not** do and you must own at the caller level:
|
|
201
201
|
|
package/dist/index.js
CHANGED
|
@@ -30179,15 +30179,29 @@ function checkDestructiveRateLimit(now = Date.now()) {
|
|
|
30179
30179
|
function isStoreAllowlistActive() {
|
|
30180
30180
|
return loadOptions().allowedStoreIds !== null;
|
|
30181
30181
|
}
|
|
30182
|
-
function
|
|
30183
|
-
if (
|
|
30184
|
-
|
|
30185
|
-
if (
|
|
30186
|
-
|
|
30187
|
-
|
|
30188
|
-
|
|
30189
|
-
|
|
30190
|
-
|
|
30182
|
+
function isPresent(value) {
|
|
30183
|
+
if (value === void 0 || value === null) return false;
|
|
30184
|
+
if (typeof value === "string" && value === "") return false;
|
|
30185
|
+
if (Array.isArray(value) && value.length === 0) return false;
|
|
30186
|
+
return true;
|
|
30187
|
+
}
|
|
30188
|
+
function checkStoreScopedToolInput(tool, input) {
|
|
30189
|
+
const toolAcceptsStoreId = "storeId" in tool.inputSchema.shape;
|
|
30190
|
+
if (toolAcceptsStoreId) {
|
|
30191
|
+
const raw = input.storeId;
|
|
30192
|
+
if (raw !== void 0 && raw !== null && raw !== "") {
|
|
30193
|
+
checkStoreAllowed(String(raw));
|
|
30194
|
+
} else if (isStoreAllowlistActive()) {
|
|
30195
|
+
throw new GuardrailError("storeId is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set");
|
|
30196
|
+
}
|
|
30197
|
+
}
|
|
30198
|
+
if (tool.requiredFilters && tool.requiredFilters.length > 0 && isStoreAllowlistActive()) {
|
|
30199
|
+
const anyPresent = tool.requiredFilters.some((key) => isPresent(input[key]));
|
|
30200
|
+
if (!anyPresent) {
|
|
30201
|
+
throw new GuardrailError(
|
|
30202
|
+
`At least one of [${tool.requiredFilters.join(", ")}] is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set`
|
|
30203
|
+
);
|
|
30204
|
+
}
|
|
30191
30205
|
}
|
|
30192
30206
|
}
|
|
30193
30207
|
function isDestructiveCall(tool, input) {
|
|
@@ -30196,11 +30210,35 @@ function isDestructiveCall(tool, input) {
|
|
|
30196
30210
|
}
|
|
30197
30211
|
|
|
30198
30212
|
// src/logger.ts
|
|
30199
|
-
function
|
|
30200
|
-
|
|
30213
|
+
function getLogLevel() {
|
|
30214
|
+
const v = process.env.LEMONSQUEEZY_LOG;
|
|
30215
|
+
if (v === "json" || v === "all") return "all";
|
|
30216
|
+
if (v === "audit") return "audit";
|
|
30217
|
+
if (v === "error") return "error";
|
|
30218
|
+
return "off";
|
|
30219
|
+
}
|
|
30220
|
+
var ERROR_STATUS_TAGS = /* @__PURE__ */ new Set(["error", "exception", "guardrail_block", "timeout", "network_error"]);
|
|
30221
|
+
function isErrorEntry(entry) {
|
|
30222
|
+
if (entry.error !== void 0) return true;
|
|
30223
|
+
if (typeof entry.status === "string") return ERROR_STATUS_TAGS.has(entry.status);
|
|
30224
|
+
if (typeof entry.status === "number") return entry.status >= 400;
|
|
30225
|
+
return false;
|
|
30226
|
+
}
|
|
30227
|
+
function shouldLog(entry, level) {
|
|
30228
|
+
switch (level) {
|
|
30229
|
+
case "off":
|
|
30230
|
+
return false;
|
|
30231
|
+
case "all":
|
|
30232
|
+
return true;
|
|
30233
|
+
case "audit":
|
|
30234
|
+
return entry.audit === true || isErrorEntry(entry);
|
|
30235
|
+
case "error":
|
|
30236
|
+
return isErrorEntry(entry);
|
|
30237
|
+
}
|
|
30201
30238
|
}
|
|
30202
30239
|
function logEvent(entry) {
|
|
30203
|
-
|
|
30240
|
+
const level = getLogLevel();
|
|
30241
|
+
if (!shouldLog(entry, level)) return;
|
|
30204
30242
|
try {
|
|
30205
30243
|
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry });
|
|
30206
30244
|
process.stderr.write(`${line}
|
|
@@ -30228,10 +30266,46 @@ function logEvent(entry) {
|
|
|
30228
30266
|
}
|
|
30229
30267
|
}
|
|
30230
30268
|
|
|
30269
|
+
// src/redact.ts
|
|
30270
|
+
var SECRET_KEY_RE = /^(secret|password|token|api[_-]?key|bearer|authorization|signing[_-]?secret)$/i;
|
|
30271
|
+
var REDACTED = "[REDACTED]";
|
|
30272
|
+
var CIRCULAR = "[CIRCULAR]";
|
|
30273
|
+
var MAX_DEPTH = 32;
|
|
30274
|
+
function isPlainObject3(value) {
|
|
30275
|
+
if (value === null || typeof value !== "object") return false;
|
|
30276
|
+
const proto = Object.getPrototypeOf(value);
|
|
30277
|
+
return proto === Object.prototype || proto === null;
|
|
30278
|
+
}
|
|
30279
|
+
function redactInner(value, visited, depth) {
|
|
30280
|
+
if (depth > MAX_DEPTH) return CIRCULAR;
|
|
30281
|
+
if (value === null || typeof value !== "object") return value;
|
|
30282
|
+
if (Array.isArray(value)) {
|
|
30283
|
+
if (visited.has(value)) return CIRCULAR;
|
|
30284
|
+
visited.add(value);
|
|
30285
|
+
return value.map((item) => redactInner(item, visited, depth + 1));
|
|
30286
|
+
}
|
|
30287
|
+
if (!isPlainObject3(value)) return value;
|
|
30288
|
+
if (visited.has(value)) return CIRCULAR;
|
|
30289
|
+
visited.add(value);
|
|
30290
|
+
const out = {};
|
|
30291
|
+
for (const [key, val] of Object.entries(value)) {
|
|
30292
|
+
if (SECRET_KEY_RE.test(key)) {
|
|
30293
|
+
out[key] = REDACTED;
|
|
30294
|
+
} else {
|
|
30295
|
+
out[key] = redactInner(val, visited, depth + 1);
|
|
30296
|
+
}
|
|
30297
|
+
}
|
|
30298
|
+
return out;
|
|
30299
|
+
}
|
|
30300
|
+
function redactSecrets(input) {
|
|
30301
|
+
return redactInner(input, /* @__PURE__ */ new WeakSet(), 0);
|
|
30302
|
+
}
|
|
30303
|
+
|
|
30231
30304
|
// src/retry.ts
|
|
30232
30305
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
30233
30306
|
var DEFAULT_RETRY_WAIT_MS = 1e3;
|
|
30234
30307
|
var MAX_RETRY_WAIT_MS = 3e4;
|
|
30308
|
+
var OVERALL_DEADLINE_MS = 9e4;
|
|
30235
30309
|
var DEFAULT_MAX_ATTEMPTS = 4;
|
|
30236
30310
|
var BASE_BACKOFF_MS = 250;
|
|
30237
30311
|
var JITTER_FRACTION = 0.25;
|
|
@@ -30251,6 +30325,19 @@ function isAbortTimeoutError(err) {
|
|
|
30251
30325
|
const e = err;
|
|
30252
30326
|
return e.name === "TimeoutError" || e.name === "AbortError" || e.code === "ABORT_ERR";
|
|
30253
30327
|
}
|
|
30328
|
+
function isRetryTimeoutError(err) {
|
|
30329
|
+
if (!err || typeof err !== "object") return false;
|
|
30330
|
+
const e = err;
|
|
30331
|
+
return e.name === "TimeoutError" && typeof e.elapsedMs === "number" && typeof e.attempts === "number";
|
|
30332
|
+
}
|
|
30333
|
+
function makeRetryTimeoutError(elapsedMs, attempts, cause) {
|
|
30334
|
+
const err = new Error("Request timed out");
|
|
30335
|
+
err.name = "TimeoutError";
|
|
30336
|
+
err.elapsedMs = elapsedMs;
|
|
30337
|
+
err.attempts = attempts;
|
|
30338
|
+
if (cause !== void 0) err.cause = cause;
|
|
30339
|
+
return err;
|
|
30340
|
+
}
|
|
30254
30341
|
function backoffDelay(attempt, rand = Math.random) {
|
|
30255
30342
|
const base = BASE_BACKOFF_MS * 2 ** (attempt - 1);
|
|
30256
30343
|
const jitter = rand() * base * JITTER_FRACTION;
|
|
@@ -30262,31 +30349,54 @@ async function fetchWithRetry(url2, init, opts) {
|
|
|
30262
30349
|
const sleep = opts.sleep ?? defaultSleep;
|
|
30263
30350
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
30264
30351
|
const rand = opts.rand ?? Math.random;
|
|
30352
|
+
const deadlineMs = opts.deadlineMs ?? OVERALL_DEADLINE_MS;
|
|
30353
|
+
const now = opts.now ?? Date.now;
|
|
30354
|
+
const startedAt = now();
|
|
30355
|
+
const deadlineAt = startedAt + deadlineMs;
|
|
30356
|
+
let attempts = 0;
|
|
30265
30357
|
let lastError;
|
|
30358
|
+
let lastResponse;
|
|
30266
30359
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
30360
|
+
if (attempt > 1 && now() >= deadlineAt) {
|
|
30361
|
+
if (lastResponse) return lastResponse;
|
|
30362
|
+
throw makeRetryTimeoutError(now() - startedAt, attempts, lastError);
|
|
30363
|
+
}
|
|
30364
|
+
attempts = attempt;
|
|
30267
30365
|
try {
|
|
30268
30366
|
const res = await fetchImpl(url2, { ...init, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
30367
|
+
lastResponse = res;
|
|
30269
30368
|
if (res.status === 429) {
|
|
30270
30369
|
if (attempt === maxAttempts) return res;
|
|
30271
30370
|
const waitMs = parseRetryAfterMs(res.headers.get("retry-after"));
|
|
30272
30371
|
if (waitMs > MAX_RETRY_WAIT_MS) return res;
|
|
30372
|
+
if (now() + waitMs >= deadlineAt) return res;
|
|
30273
30373
|
await sleep(waitMs);
|
|
30274
30374
|
continue;
|
|
30275
30375
|
}
|
|
30276
30376
|
if (res.status >= 500 && res.status < 600 && opts.idempotent && attempt < maxAttempts) {
|
|
30277
|
-
|
|
30377
|
+
const waitMs = backoffDelay(attempt, rand);
|
|
30378
|
+
if (now() + waitMs >= deadlineAt) return res;
|
|
30379
|
+
await sleep(waitMs);
|
|
30278
30380
|
continue;
|
|
30279
30381
|
}
|
|
30280
30382
|
return res;
|
|
30281
30383
|
} catch (err) {
|
|
30282
30384
|
lastError = err;
|
|
30283
30385
|
if (isAbortTimeoutError(err)) {
|
|
30284
|
-
if (!opts.idempotent || attempt === maxAttempts)
|
|
30285
|
-
|
|
30386
|
+
if (!opts.idempotent || attempt === maxAttempts) {
|
|
30387
|
+
throw makeRetryTimeoutError(now() - startedAt, attempts, err);
|
|
30388
|
+
}
|
|
30389
|
+
const waitMs = backoffDelay(attempt, rand);
|
|
30390
|
+
if (now() + waitMs >= deadlineAt) {
|
|
30391
|
+
throw makeRetryTimeoutError(now() - startedAt, attempts, err);
|
|
30392
|
+
}
|
|
30393
|
+
await sleep(waitMs);
|
|
30286
30394
|
continue;
|
|
30287
30395
|
}
|
|
30288
30396
|
if (err instanceof TypeError && opts.idempotent && attempt < maxAttempts) {
|
|
30289
|
-
|
|
30397
|
+
const waitMs = backoffDelay(attempt, rand);
|
|
30398
|
+
if (now() + waitMs >= deadlineAt) throw err;
|
|
30399
|
+
await sleep(waitMs);
|
|
30290
30400
|
continue;
|
|
30291
30401
|
}
|
|
30292
30402
|
throw err;
|
|
@@ -30330,10 +30440,21 @@ function parseCommand(cmd) {
|
|
|
30330
30440
|
if (parts.length === 0) throw new Error("LEMONSQUEEZY_API_KEY_COMMAND is empty");
|
|
30331
30441
|
return { command: parts[0], args: parts.slice(1) };
|
|
30332
30442
|
}
|
|
30443
|
+
function fromCache(fingerprint) {
|
|
30444
|
+
if (cached2 && cached2.fingerprint === fingerprint && cached2.expiresAt > Date.now()) {
|
|
30445
|
+
return cached2.key;
|
|
30446
|
+
}
|
|
30447
|
+
return null;
|
|
30448
|
+
}
|
|
30449
|
+
function intoCache(fingerprint, key) {
|
|
30450
|
+
cached2 = { fingerprint, key, expiresAt: Date.now() + CACHE_TTL_MS };
|
|
30451
|
+
}
|
|
30333
30452
|
async function loadApiKey() {
|
|
30334
|
-
if (cached2 && cached2.expiresAt > Date.now()) return cached2.key;
|
|
30335
30453
|
const cmdStr = process.env.LEMONSQUEEZY_API_KEY_COMMAND;
|
|
30336
30454
|
if (cmdStr && cmdStr.trim() !== "") {
|
|
30455
|
+
const fingerprint2 = `cmd:${cmdStr}`;
|
|
30456
|
+
const hit2 = fromCache(fingerprint2);
|
|
30457
|
+
if (hit2 !== null) return hit2;
|
|
30337
30458
|
const { command, args } = parseCommand(cmdStr);
|
|
30338
30459
|
let stdout;
|
|
30339
30460
|
try {
|
|
@@ -30346,23 +30467,31 @@ async function loadApiKey() {
|
|
|
30346
30467
|
const msg = err instanceof Error ? err.message : String(err);
|
|
30347
30468
|
throw new Error(`LEMONSQUEEZY_API_KEY_COMMAND failed: ${msg}`);
|
|
30348
30469
|
}
|
|
30349
|
-
const
|
|
30350
|
-
if (!
|
|
30351
|
-
|
|
30352
|
-
return
|
|
30470
|
+
const key = stdout.trim();
|
|
30471
|
+
if (!key) throw new Error("LEMONSQUEEZY_API_KEY_COMMAND produced empty output");
|
|
30472
|
+
intoCache(fingerprint2, key);
|
|
30473
|
+
return key;
|
|
30353
30474
|
}
|
|
30354
|
-
const
|
|
30355
|
-
if (!
|
|
30475
|
+
const raw = process.env.LEMONSQUEEZY_API_KEY;
|
|
30476
|
+
if (!raw) {
|
|
30356
30477
|
throw new Error("LEMONSQUEEZY_API_KEY or LEMONSQUEEZY_API_KEY_COMMAND environment variable is required.");
|
|
30357
30478
|
}
|
|
30358
|
-
if (
|
|
30479
|
+
if (raw.trim() === "") {
|
|
30359
30480
|
throw new Error("LEMONSQUEEZY_API_KEY is set but empty. Provide a valid API key.");
|
|
30360
30481
|
}
|
|
30361
|
-
|
|
30482
|
+
const fingerprint = `env:${raw}`;
|
|
30483
|
+
const hit = fromCache(fingerprint);
|
|
30484
|
+
if (hit !== null) return hit;
|
|
30485
|
+
intoCache(fingerprint, raw);
|
|
30486
|
+
return raw;
|
|
30487
|
+
}
|
|
30488
|
+
function invalidateApiKeyCache() {
|
|
30489
|
+
cached2 = null;
|
|
30362
30490
|
}
|
|
30363
30491
|
|
|
30364
30492
|
// src/api.ts
|
|
30365
30493
|
var BASE_URL = "https://api.lemonsqueezy.com/v1";
|
|
30494
|
+
var lsIdSchema = external_exports3.string().max(1e4).regex(/^[1-9]\d*$/, "ID must be a positive integer string (e.g. '12345')");
|
|
30366
30495
|
function encodePath(segment) {
|
|
30367
30496
|
return encodeURIComponent(String(segment));
|
|
30368
30497
|
}
|
|
@@ -30390,6 +30519,14 @@ function buildQuery(params) {
|
|
|
30390
30519
|
function decorateError(error48, requestId) {
|
|
30391
30520
|
return requestId ? `${error48} (request_id: ${requestId})` : error48;
|
|
30392
30521
|
}
|
|
30522
|
+
function formatTimeoutMessage(err, fallbackElapsedMs) {
|
|
30523
|
+
if (isRetryTimeoutError(err)) {
|
|
30524
|
+
const seconds2 = Math.max(1, Math.round(err.elapsedMs / 1e3));
|
|
30525
|
+
return `Request timed out after ${seconds2}s (${err.attempts} attempts)`;
|
|
30526
|
+
}
|
|
30527
|
+
const seconds = Math.max(1, Math.round(fallbackElapsedMs / 1e3));
|
|
30528
|
+
return `Request timed out after ${seconds}s (1 attempts)`;
|
|
30529
|
+
}
|
|
30393
30530
|
async function apiRequest(method, path, body) {
|
|
30394
30531
|
const start = Date.now();
|
|
30395
30532
|
const apiKey = await loadApiKey();
|
|
@@ -30410,7 +30547,7 @@ async function apiRequest(method, path, body) {
|
|
|
30410
30547
|
} catch (err) {
|
|
30411
30548
|
const latency_ms2 = Date.now() - start;
|
|
30412
30549
|
if (isAbortTimeoutError(err)) {
|
|
30413
|
-
const error48 =
|
|
30550
|
+
const error48 = formatTimeoutMessage(err, latency_ms2);
|
|
30414
30551
|
logEvent({ event: "http_call", method, path, status: "timeout", latency_ms: latency_ms2, error: error48 });
|
|
30415
30552
|
return { ok: false, status: 0, error: error48 };
|
|
30416
30553
|
}
|
|
@@ -30421,6 +30558,9 @@ async function apiRequest(method, path, body) {
|
|
|
30421
30558
|
const latency_ms = Date.now() - start;
|
|
30422
30559
|
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
30423
30560
|
if (!res.ok) {
|
|
30561
|
+
if (res.status === 401 || res.status === 403) {
|
|
30562
|
+
invalidateApiKeyCache();
|
|
30563
|
+
}
|
|
30424
30564
|
const errorBody = await res.text();
|
|
30425
30565
|
try {
|
|
30426
30566
|
const parsed = JSON.parse(errorBody);
|
|
@@ -30494,7 +30634,7 @@ async function licenseRequest(path, body) {
|
|
|
30494
30634
|
} catch (err) {
|
|
30495
30635
|
const latency_ms2 = Date.now() - start;
|
|
30496
30636
|
if (isAbortTimeoutError(err)) {
|
|
30497
|
-
const error48 =
|
|
30637
|
+
const error48 = formatTimeoutMessage(err, latency_ms2);
|
|
30498
30638
|
logEvent({ event: "http_call", method: "POST", path, status: "timeout", latency_ms: latency_ms2, error: error48 });
|
|
30499
30639
|
return { ok: false, status: 0, error: error48 };
|
|
30500
30640
|
}
|
|
@@ -30610,14 +30750,14 @@ var affiliateTools = [
|
|
|
30610
30750
|
openWorldHint: true
|
|
30611
30751
|
},
|
|
30612
30752
|
inputSchema: external_exports3.object({
|
|
30613
|
-
affiliateId:
|
|
30753
|
+
affiliateId: lsIdSchema.describe("The affiliate ID"),
|
|
30614
30754
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,user')")
|
|
30615
30755
|
}),
|
|
30616
30756
|
handler: getHandler("/affiliates", "affiliateId")
|
|
30617
30757
|
},
|
|
30618
30758
|
{
|
|
30619
30759
|
name: "ls_list_affiliates",
|
|
30620
|
-
description: "List all affiliates for the authenticated user's stores, optionally filtered by user email. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
30760
|
+
description: "List all affiliates for the authenticated user's stores, optionally filtered by user email. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool can still return affiliates tied to non-allowed stores -- the endpoint has no parent ID filter to scope by. Pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
30621
30761
|
annotations: {
|
|
30622
30762
|
title: "List affiliates",
|
|
30623
30763
|
readOnlyHint: true,
|
|
@@ -30648,7 +30788,7 @@ var checkoutTools = [
|
|
|
30648
30788
|
openWorldHint: true
|
|
30649
30789
|
},
|
|
30650
30790
|
inputSchema: external_exports3.object({
|
|
30651
|
-
checkoutId:
|
|
30791
|
+
checkoutId: lsIdSchema.describe("The checkout ID"),
|
|
30652
30792
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variant')")
|
|
30653
30793
|
}),
|
|
30654
30794
|
handler: getHandler("/checkouts", "checkoutId")
|
|
@@ -30664,8 +30804,8 @@ var checkoutTools = [
|
|
|
30664
30804
|
openWorldHint: true
|
|
30665
30805
|
},
|
|
30666
30806
|
inputSchema: external_exports3.object({
|
|
30667
|
-
storeId:
|
|
30668
|
-
variantId:
|
|
30807
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
30808
|
+
variantId: lsIdSchema.optional().describe("Filter by variant ID"),
|
|
30669
30809
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variant')"),
|
|
30670
30810
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
30671
30811
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
@@ -30683,11 +30823,11 @@ var checkoutTools = [
|
|
|
30683
30823
|
openWorldHint: true
|
|
30684
30824
|
},
|
|
30685
30825
|
inputSchema: external_exports3.object({
|
|
30686
|
-
storeId:
|
|
30687
|
-
variantId:
|
|
30826
|
+
storeId: lsIdSchema.describe("The store ID"),
|
|
30827
|
+
variantId: lsIdSchema.describe("The variant ID for the product being purchased"),
|
|
30688
30828
|
customPrice: external_exports3.number().int().min(0).optional().describe("Custom price in cents (overrides the variant price)"),
|
|
30689
|
-
enabledVariants: external_exports3.array(
|
|
30690
|
-
email: external_exports3.string().max(
|
|
30829
|
+
enabledVariants: external_exports3.array(lsIdSchema).optional().describe("Array of variant IDs to show on the checkout (for products with multiple variants)"),
|
|
30830
|
+
email: external_exports3.string().email().max(320).optional().describe("Prefill customer email"),
|
|
30691
30831
|
name: external_exports3.string().max(1e4).optional().describe("Prefill customer name"),
|
|
30692
30832
|
billingAddressCountry: external_exports3.string().max(1e4).optional().describe("Prefill billing country (ISO 3166-1 alpha-2)"),
|
|
30693
30833
|
billingAddressZip: external_exports3.string().max(1e4).optional().describe("Prefill billing ZIP/postal code"),
|
|
@@ -30743,7 +30883,7 @@ var customerTools = [
|
|
|
30743
30883
|
openWorldHint: true
|
|
30744
30884
|
},
|
|
30745
30885
|
inputSchema: external_exports3.object({
|
|
30746
|
-
customerId:
|
|
30886
|
+
customerId: lsIdSchema.describe("The customer ID"),
|
|
30747
30887
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,orders,subscriptions,license-keys')")
|
|
30748
30888
|
}),
|
|
30749
30889
|
handler: getHandler("/customers", "customerId")
|
|
@@ -30759,7 +30899,7 @@ var customerTools = [
|
|
|
30759
30899
|
openWorldHint: true
|
|
30760
30900
|
},
|
|
30761
30901
|
inputSchema: external_exports3.object({
|
|
30762
|
-
storeId:
|
|
30902
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
30763
30903
|
email: external_exports3.string().email().max(320).optional().describe("Filter by customer email"),
|
|
30764
30904
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,orders,subscriptions,license-keys')"),
|
|
30765
30905
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
@@ -30778,7 +30918,7 @@ var customerTools = [
|
|
|
30778
30918
|
openWorldHint: true
|
|
30779
30919
|
},
|
|
30780
30920
|
inputSchema: external_exports3.object({
|
|
30781
|
-
storeId:
|
|
30921
|
+
storeId: lsIdSchema.describe("The store ID to create the customer in"),
|
|
30782
30922
|
name: external_exports3.string().max(1e4).describe("Customer's full name"),
|
|
30783
30923
|
email: external_exports3.string().email().max(320).describe("Customer's email address"),
|
|
30784
30924
|
city: external_exports3.string().max(1e4).optional().describe("Customer's city"),
|
|
@@ -30806,7 +30946,7 @@ var customerTools = [
|
|
|
30806
30946
|
},
|
|
30807
30947
|
{
|
|
30808
30948
|
name: "ls_update_customer",
|
|
30809
|
-
description: "Update an existing customer's name, email, city, region, country, or status.",
|
|
30949
|
+
description: "Update an existing customer's name, email, city, region, country, or status. The only supported status value is 'archived' \u2014 use ls_archive_customer for the dedicated, audit-tagged path.",
|
|
30810
30950
|
annotations: {
|
|
30811
30951
|
title: "Update customer",
|
|
30812
30952
|
readOnlyHint: false,
|
|
@@ -30818,16 +30958,19 @@ var customerTools = [
|
|
|
30818
30958
|
// ls_archive_customer and must engage the same rate limiter / audit log;
|
|
30819
30959
|
// otherwise the dedicated archive tool's destructive flag becomes a side
|
|
30820
30960
|
// channel anyone can route around. Other field edits (name, email,
|
|
30821
|
-
// address) stay on the regular path.
|
|
30961
|
+
// address) stay on the regular path. The schema constrains `status` to
|
|
30962
|
+
// the literal "archived" so a typo ("archive", "Archived") fails at
|
|
30963
|
+
// validation rather than slipping past the predicate as a non-destructive
|
|
30964
|
+
// PATCH that the API would 422 anyway.
|
|
30822
30965
|
isDestructive: (input) => input.status === "archived",
|
|
30823
30966
|
inputSchema: external_exports3.object({
|
|
30824
|
-
customerId:
|
|
30967
|
+
customerId: lsIdSchema.describe("The customer ID to update"),
|
|
30825
30968
|
name: external_exports3.string().max(1e4).optional().describe("New name"),
|
|
30826
30969
|
email: external_exports3.string().email().max(320).optional().describe("New email"),
|
|
30827
30970
|
city: external_exports3.string().max(1e4).optional().describe("New city"),
|
|
30828
30971
|
region: external_exports3.string().max(1e4).optional().describe("New region/state"),
|
|
30829
30972
|
country: external_exports3.string().max(1e4).optional().describe("New country (ISO 3166-1 alpha-2 code)"),
|
|
30830
|
-
status: external_exports3.
|
|
30973
|
+
status: external_exports3.literal("archived").optional().describe("Set to 'archived' to archive the customer. Equivalent to calling ls_archive_customer.")
|
|
30831
30974
|
}),
|
|
30832
30975
|
handler: async (input) => {
|
|
30833
30976
|
const attributes = {};
|
|
@@ -30857,7 +31000,7 @@ var customerTools = [
|
|
|
30857
31000
|
openWorldHint: true
|
|
30858
31001
|
},
|
|
30859
31002
|
inputSchema: external_exports3.object({
|
|
30860
|
-
customerId:
|
|
31003
|
+
customerId: lsIdSchema.describe("The customer ID to archive")
|
|
30861
31004
|
}),
|
|
30862
31005
|
handler: async (input) => {
|
|
30863
31006
|
return apiPatch(`/customers/${encodePath(input.customerId)}`, {
|
|
@@ -30884,14 +31027,14 @@ var discountRedemptionTools = [
|
|
|
30884
31027
|
openWorldHint: true
|
|
30885
31028
|
},
|
|
30886
31029
|
inputSchema: external_exports3.object({
|
|
30887
|
-
discountRedemptionId:
|
|
31030
|
+
discountRedemptionId: lsIdSchema.describe("The discount redemption ID"),
|
|
30888
31031
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'discount,order')")
|
|
30889
31032
|
}),
|
|
30890
31033
|
handler: getHandler("/discount-redemptions", "discountRedemptionId")
|
|
30891
31034
|
},
|
|
30892
31035
|
{
|
|
30893
31036
|
name: "ls_list_discount_redemptions",
|
|
30894
|
-
description: "List all discount redemptions, optionally filtered by discount or order. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31037
|
+
description: "List all discount redemptions, optionally filtered by discount or order. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: discountId, orderId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
30895
31038
|
annotations: {
|
|
30896
31039
|
title: "List discount redemptions",
|
|
30897
31040
|
readOnlyHint: true,
|
|
@@ -30900,12 +31043,13 @@ var discountRedemptionTools = [
|
|
|
30900
31043
|
openWorldHint: true
|
|
30901
31044
|
},
|
|
30902
31045
|
inputSchema: external_exports3.object({
|
|
30903
|
-
discountId:
|
|
30904
|
-
orderId:
|
|
31046
|
+
discountId: lsIdSchema.optional().describe("Filter by discount ID"),
|
|
31047
|
+
orderId: lsIdSchema.optional().describe("Filter by order ID"),
|
|
30905
31048
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'discount,order')"),
|
|
30906
31049
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
30907
31050
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
30908
31051
|
}),
|
|
31052
|
+
requiredFilters: ["discountId", "orderId"],
|
|
30909
31053
|
handler: listHandler("/discount-redemptions", { discountId: "discount_id", orderId: "order_id" })
|
|
30910
31054
|
}
|
|
30911
31055
|
];
|
|
@@ -30923,7 +31067,7 @@ var discountTools = [
|
|
|
30923
31067
|
openWorldHint: true
|
|
30924
31068
|
},
|
|
30925
31069
|
inputSchema: external_exports3.object({
|
|
30926
|
-
discountId:
|
|
31070
|
+
discountId: lsIdSchema.describe("The discount ID"),
|
|
30927
31071
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants,discount-redemptions')")
|
|
30928
31072
|
}),
|
|
30929
31073
|
handler: getHandler("/discounts", "discountId")
|
|
@@ -30939,7 +31083,7 @@ var discountTools = [
|
|
|
30939
31083
|
openWorldHint: true
|
|
30940
31084
|
},
|
|
30941
31085
|
inputSchema: external_exports3.object({
|
|
30942
|
-
storeId:
|
|
31086
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
30943
31087
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants,discount-redemptions')"),
|
|
30944
31088
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
30945
31089
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
@@ -30957,7 +31101,7 @@ var discountTools = [
|
|
|
30957
31101
|
openWorldHint: true
|
|
30958
31102
|
},
|
|
30959
31103
|
inputSchema: external_exports3.object({
|
|
30960
|
-
storeId:
|
|
31104
|
+
storeId: lsIdSchema.describe("The store ID to create the discount in"),
|
|
30961
31105
|
name: external_exports3.string().max(1e4).describe("Internal name for the discount"),
|
|
30962
31106
|
code: external_exports3.string().max(1e4).describe("The discount code customers will enter (e.g. 'SAVE20')"),
|
|
30963
31107
|
amount: external_exports3.number().int().min(1).describe(
|
|
@@ -30972,7 +31116,7 @@ var discountTools = [
|
|
|
30972
31116
|
startsAt: external_exports3.string().max(1e4).optional().describe("When the discount becomes active (ISO 8601 format)"),
|
|
30973
31117
|
expiresAt: external_exports3.string().max(1e4).optional().describe("When the discount expires (ISO 8601 format)"),
|
|
30974
31118
|
isLimitedToProducts: external_exports3.boolean().optional().describe("If true, the discount only applies to specific variants (set via variantIds)"),
|
|
30975
|
-
variantIds: external_exports3.array(
|
|
31119
|
+
variantIds: external_exports3.array(lsIdSchema).optional().describe("Array of variant IDs this discount applies to (requires isLimitedToProducts: true)")
|
|
30976
31120
|
}),
|
|
30977
31121
|
handler: async (input) => {
|
|
30978
31122
|
const attributes = {
|
|
@@ -31015,7 +31159,7 @@ var discountTools = [
|
|
|
31015
31159
|
openWorldHint: true
|
|
31016
31160
|
},
|
|
31017
31161
|
inputSchema: external_exports3.object({
|
|
31018
|
-
discountId:
|
|
31162
|
+
discountId: lsIdSchema.describe("The discount ID to delete")
|
|
31019
31163
|
}),
|
|
31020
31164
|
handler: async (input) => {
|
|
31021
31165
|
return apiDelete(`/discounts/${encodePath(input.discountId)}`);
|
|
@@ -31036,14 +31180,14 @@ var fileTools = [
|
|
|
31036
31180
|
openWorldHint: true
|
|
31037
31181
|
},
|
|
31038
31182
|
inputSchema: external_exports3.object({
|
|
31039
|
-
fileId:
|
|
31183
|
+
fileId: lsIdSchema.describe("The file ID"),
|
|
31040
31184
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')")
|
|
31041
31185
|
}),
|
|
31042
31186
|
handler: getHandler("/files", "fileId")
|
|
31043
31187
|
},
|
|
31044
31188
|
{
|
|
31045
31189
|
name: "ls_list_files",
|
|
31046
|
-
description: "List all files, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31190
|
+
description: "List all files, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: variantId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31047
31191
|
annotations: {
|
|
31048
31192
|
title: "List files",
|
|
31049
31193
|
readOnlyHint: true,
|
|
@@ -31052,11 +31196,12 @@ var fileTools = [
|
|
|
31052
31196
|
openWorldHint: true
|
|
31053
31197
|
},
|
|
31054
31198
|
inputSchema: external_exports3.object({
|
|
31055
|
-
variantId:
|
|
31199
|
+
variantId: lsIdSchema.optional().describe("Filter by variant ID"),
|
|
31056
31200
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')"),
|
|
31057
31201
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31058
31202
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31059
31203
|
}),
|
|
31204
|
+
requiredFilters: ["variantId"],
|
|
31060
31205
|
handler: listHandler("/files", { variantId: "variant_id" })
|
|
31061
31206
|
}
|
|
31062
31207
|
];
|
|
@@ -31074,14 +31219,14 @@ var licenseKeyInstanceTools = [
|
|
|
31074
31219
|
openWorldHint: true
|
|
31075
31220
|
},
|
|
31076
31221
|
inputSchema: external_exports3.object({
|
|
31077
|
-
licenseKeyInstanceId:
|
|
31222
|
+
licenseKeyInstanceId: lsIdSchema.describe("The license key instance ID"),
|
|
31078
31223
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'license-key')")
|
|
31079
31224
|
}),
|
|
31080
31225
|
handler: getHandler("/license-key-instances", "licenseKeyInstanceId")
|
|
31081
31226
|
},
|
|
31082
31227
|
{
|
|
31083
31228
|
name: "ls_list_license_key_instances",
|
|
31084
|
-
description: "List all license key instances (activations), optionally filtered by license key. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31229
|
+
description: "List all license key instances (activations), optionally filtered by license key. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: licenseKeyId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31085
31230
|
annotations: {
|
|
31086
31231
|
title: "List license key instances",
|
|
31087
31232
|
readOnlyHint: true,
|
|
@@ -31090,11 +31235,12 @@ var licenseKeyInstanceTools = [
|
|
|
31090
31235
|
openWorldHint: true
|
|
31091
31236
|
},
|
|
31092
31237
|
inputSchema: external_exports3.object({
|
|
31093
|
-
licenseKeyId:
|
|
31238
|
+
licenseKeyId: lsIdSchema.optional().describe("Filter by license key ID"),
|
|
31094
31239
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'license-key')"),
|
|
31095
31240
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31096
31241
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31097
31242
|
}),
|
|
31243
|
+
requiredFilters: ["licenseKeyId"],
|
|
31098
31244
|
handler: listHandler("/license-key-instances", { licenseKeyId: "license_key_id" })
|
|
31099
31245
|
}
|
|
31100
31246
|
];
|
|
@@ -31112,7 +31258,7 @@ var licenseKeyTools = [
|
|
|
31112
31258
|
openWorldHint: true
|
|
31113
31259
|
},
|
|
31114
31260
|
inputSchema: external_exports3.object({
|
|
31115
|
-
licenseKeyId:
|
|
31261
|
+
licenseKeyId: lsIdSchema.describe("The license key ID"),
|
|
31116
31262
|
include: external_exports3.string().max(1e4).optional().describe(
|
|
31117
31263
|
"Comma-separated related resources to include (e.g. 'store,customer,order,order-item,product,license-key-instances')"
|
|
31118
31264
|
)
|
|
@@ -31130,10 +31276,10 @@ var licenseKeyTools = [
|
|
|
31130
31276
|
openWorldHint: true
|
|
31131
31277
|
},
|
|
31132
31278
|
inputSchema: external_exports3.object({
|
|
31133
|
-
storeId:
|
|
31134
|
-
orderId:
|
|
31135
|
-
orderItemId:
|
|
31136
|
-
productId:
|
|
31279
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
31280
|
+
orderId: lsIdSchema.optional().describe("Filter by order ID"),
|
|
31281
|
+
orderItemId: lsIdSchema.optional().describe("Filter by order item ID"),
|
|
31282
|
+
productId: lsIdSchema.optional().describe("Filter by product ID"),
|
|
31137
31283
|
include: external_exports3.string().max(1e4).optional().describe(
|
|
31138
31284
|
"Comma-separated related resources to include (e.g. 'store,customer,order,order-item,product,license-key-instances')"
|
|
31139
31285
|
),
|
|
@@ -31157,13 +31303,16 @@ var licenseKeyTools = [
|
|
|
31157
31303
|
idempotentHint: true,
|
|
31158
31304
|
openWorldHint: true
|
|
31159
31305
|
},
|
|
31160
|
-
// Disabling a license key revokes a customer's access.
|
|
31161
|
-
//
|
|
31162
|
-
//
|
|
31163
|
-
//
|
|
31164
|
-
|
|
31306
|
+
// Disabling a license key revokes a customer's access outright. Changing
|
|
31307
|
+
// the activation limit can also revoke access -- setting it to 0, or to
|
|
31308
|
+
// any value below the customer's current activation count, kicks
|
|
31309
|
+
// already-activated instances offline. We can't tell from the input alone
|
|
31310
|
+
// whether a given limit change shrinks or grows, so treat ANY
|
|
31311
|
+
// `activationLimit` change as destructive alongside `disabled: true`.
|
|
31312
|
+
// Benign edits (expiry) stay on the regular path.
|
|
31313
|
+
isDestructive: (input) => input.disabled === true || input.activationLimit !== void 0,
|
|
31165
31314
|
inputSchema: external_exports3.object({
|
|
31166
|
-
licenseKeyId:
|
|
31315
|
+
licenseKeyId: lsIdSchema.describe("The license key ID to update"),
|
|
31167
31316
|
activationLimit: external_exports3.number().int().min(0).optional().describe("Maximum number of activations allowed (0 = unlimited)"),
|
|
31168
31317
|
disabled: external_exports3.boolean().optional().describe("Set to true to disable this license key"),
|
|
31169
31318
|
expiresAt: external_exports3.string().max(1e4).nullable().optional().describe("Expiry date (ISO 8601 format). Set to null to remove expiry.")
|
|
@@ -31263,14 +31412,14 @@ var orderItemTools = [
|
|
|
31263
31412
|
openWorldHint: true
|
|
31264
31413
|
},
|
|
31265
31414
|
inputSchema: external_exports3.object({
|
|
31266
|
-
orderItemId:
|
|
31415
|
+
orderItemId: lsIdSchema.describe("The order item ID"),
|
|
31267
31416
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'order,product,variant')")
|
|
31268
31417
|
}),
|
|
31269
31418
|
handler: getHandler("/order-items", "orderItemId")
|
|
31270
31419
|
},
|
|
31271
31420
|
{
|
|
31272
31421
|
name: "ls_list_order_items",
|
|
31273
|
-
description: "List all order items, optionally filtered by order or product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31422
|
+
description: "List all order items, optionally filtered by order or product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: orderId, productId, variantId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31274
31423
|
annotations: {
|
|
31275
31424
|
title: "List order items",
|
|
31276
31425
|
readOnlyHint: true,
|
|
@@ -31279,13 +31428,14 @@ var orderItemTools = [
|
|
|
31279
31428
|
openWorldHint: true
|
|
31280
31429
|
},
|
|
31281
31430
|
inputSchema: external_exports3.object({
|
|
31282
|
-
orderId:
|
|
31283
|
-
productId:
|
|
31284
|
-
variantId:
|
|
31431
|
+
orderId: lsIdSchema.optional().describe("Filter by order ID"),
|
|
31432
|
+
productId: lsIdSchema.optional().describe("Filter by product ID"),
|
|
31433
|
+
variantId: lsIdSchema.optional().describe("Filter by variant ID"),
|
|
31285
31434
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'order,product,variant')"),
|
|
31286
31435
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31287
31436
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31288
31437
|
}),
|
|
31438
|
+
requiredFilters: ["orderId", "productId", "variantId"],
|
|
31289
31439
|
handler: listHandler("/order-items", { orderId: "order_id", productId: "product_id", variantId: "variant_id" })
|
|
31290
31440
|
}
|
|
31291
31441
|
];
|
|
@@ -31303,7 +31453,7 @@ var orderTools = [
|
|
|
31303
31453
|
openWorldHint: true
|
|
31304
31454
|
},
|
|
31305
31455
|
inputSchema: external_exports3.object({
|
|
31306
|
-
orderId:
|
|
31456
|
+
orderId: lsIdSchema.describe("The order ID"),
|
|
31307
31457
|
include: external_exports3.string().max(1e4).optional().describe(
|
|
31308
31458
|
"Comma-separated related resources to include (e.g. 'store,customer,order-items,subscriptions,license-keys,discount-redemptions')"
|
|
31309
31459
|
)
|
|
@@ -31321,7 +31471,7 @@ var orderTools = [
|
|
|
31321
31471
|
openWorldHint: true
|
|
31322
31472
|
},
|
|
31323
31473
|
inputSchema: external_exports3.object({
|
|
31324
|
-
storeId:
|
|
31474
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
31325
31475
|
userEmail: external_exports3.string().email().max(320).optional().describe("Filter by user email"),
|
|
31326
31476
|
include: external_exports3.string().max(1e4).optional().describe(
|
|
31327
31477
|
"Comma-separated related resources to include (e.g. 'store,customer,order-items,subscriptions,license-keys,discount-redemptions')"
|
|
@@ -31342,7 +31492,7 @@ var orderTools = [
|
|
|
31342
31492
|
openWorldHint: true
|
|
31343
31493
|
},
|
|
31344
31494
|
inputSchema: external_exports3.object({
|
|
31345
|
-
orderId:
|
|
31495
|
+
orderId: lsIdSchema.describe("The order ID"),
|
|
31346
31496
|
name: external_exports3.string().max(1e4).optional().describe("Customer name on the invoice"),
|
|
31347
31497
|
address: external_exports3.string().max(1e4).optional().describe("Customer address on the invoice"),
|
|
31348
31498
|
city: external_exports3.string().max(1e4).optional().describe("Customer city"),
|
|
@@ -31377,7 +31527,7 @@ var orderTools = [
|
|
|
31377
31527
|
openWorldHint: true
|
|
31378
31528
|
},
|
|
31379
31529
|
inputSchema: external_exports3.object({
|
|
31380
|
-
orderId:
|
|
31530
|
+
orderId: lsIdSchema.describe("The order ID to refund"),
|
|
31381
31531
|
amount: external_exports3.number().int().min(1).describe("Refund amount in cents (e.g. 1000 = $10.00)")
|
|
31382
31532
|
}),
|
|
31383
31533
|
handler: async (input) => {
|
|
@@ -31402,14 +31552,14 @@ var priceTools = [
|
|
|
31402
31552
|
openWorldHint: true
|
|
31403
31553
|
},
|
|
31404
31554
|
inputSchema: external_exports3.object({
|
|
31405
|
-
priceId:
|
|
31555
|
+
priceId: lsIdSchema.describe("The price ID"),
|
|
31406
31556
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')")
|
|
31407
31557
|
}),
|
|
31408
31558
|
handler: getHandler("/prices", "priceId")
|
|
31409
31559
|
},
|
|
31410
31560
|
{
|
|
31411
31561
|
name: "ls_list_prices",
|
|
31412
|
-
description: "List all prices, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31562
|
+
description: "List all prices, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: variantId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31413
31563
|
annotations: {
|
|
31414
31564
|
title: "List prices",
|
|
31415
31565
|
readOnlyHint: true,
|
|
@@ -31418,11 +31568,12 @@ var priceTools = [
|
|
|
31418
31568
|
openWorldHint: true
|
|
31419
31569
|
},
|
|
31420
31570
|
inputSchema: external_exports3.object({
|
|
31421
|
-
variantId:
|
|
31571
|
+
variantId: lsIdSchema.optional().describe("Filter by variant ID"),
|
|
31422
31572
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')"),
|
|
31423
31573
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31424
31574
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31425
31575
|
}),
|
|
31576
|
+
requiredFilters: ["variantId"],
|
|
31426
31577
|
handler: listHandler("/prices", { variantId: "variant_id" })
|
|
31427
31578
|
}
|
|
31428
31579
|
];
|
|
@@ -31440,7 +31591,7 @@ var productTools = [
|
|
|
31440
31591
|
openWorldHint: true
|
|
31441
31592
|
},
|
|
31442
31593
|
inputSchema: external_exports3.object({
|
|
31443
|
-
productId:
|
|
31594
|
+
productId: lsIdSchema.describe("The product ID"),
|
|
31444
31595
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants')")
|
|
31445
31596
|
}),
|
|
31446
31597
|
handler: getHandler("/products", "productId")
|
|
@@ -31456,7 +31607,7 @@ var productTools = [
|
|
|
31456
31607
|
openWorldHint: true
|
|
31457
31608
|
},
|
|
31458
31609
|
inputSchema: external_exports3.object({
|
|
31459
|
-
storeId:
|
|
31610
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
31460
31611
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants')"),
|
|
31461
31612
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31462
31613
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
@@ -31478,7 +31629,7 @@ var storeTools = [
|
|
|
31478
31629
|
openWorldHint: true
|
|
31479
31630
|
},
|
|
31480
31631
|
inputSchema: external_exports3.object({
|
|
31481
|
-
storeId:
|
|
31632
|
+
storeId: lsIdSchema.describe("The store ID"),
|
|
31482
31633
|
include: external_exports3.string().max(1e4).optional().describe(
|
|
31483
31634
|
"Comma-separated related resources to include (e.g. 'products,discounts,license-keys,subscriptions,webhooks')"
|
|
31484
31635
|
)
|
|
@@ -31519,7 +31670,7 @@ var subscriptionInvoiceTools = [
|
|
|
31519
31670
|
openWorldHint: true
|
|
31520
31671
|
},
|
|
31521
31672
|
inputSchema: external_exports3.object({
|
|
31522
|
-
subscriptionInvoiceId:
|
|
31673
|
+
subscriptionInvoiceId: lsIdSchema.describe("The subscription invoice ID"),
|
|
31523
31674
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,subscription')")
|
|
31524
31675
|
}),
|
|
31525
31676
|
handler: getHandler("/subscription-invoices", "subscriptionInvoiceId")
|
|
@@ -31535,8 +31686,8 @@ var subscriptionInvoiceTools = [
|
|
|
31535
31686
|
openWorldHint: true
|
|
31536
31687
|
},
|
|
31537
31688
|
inputSchema: external_exports3.object({
|
|
31538
|
-
storeId:
|
|
31539
|
-
subscriptionId:
|
|
31689
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
31690
|
+
subscriptionId: lsIdSchema.optional().describe("Filter by subscription ID"),
|
|
31540
31691
|
status: external_exports3.enum(["pending", "paid", "void", "refunded"]).optional().describe("Filter by invoice status"),
|
|
31541
31692
|
refunded: external_exports3.boolean().optional().describe("Filter by refunded status"),
|
|
31542
31693
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,subscription')"),
|
|
@@ -31561,7 +31712,7 @@ var subscriptionInvoiceTools = [
|
|
|
31561
31712
|
openWorldHint: true
|
|
31562
31713
|
},
|
|
31563
31714
|
inputSchema: external_exports3.object({
|
|
31564
|
-
subscriptionInvoiceId:
|
|
31715
|
+
subscriptionInvoiceId: lsIdSchema.describe("The subscription invoice ID"),
|
|
31565
31716
|
name: external_exports3.string().max(1e4).optional().describe("Customer name on the invoice"),
|
|
31566
31717
|
address: external_exports3.string().max(1e4).optional().describe("Customer address on the invoice"),
|
|
31567
31718
|
city: external_exports3.string().max(1e4).optional().describe("Customer city"),
|
|
@@ -31598,7 +31749,7 @@ var subscriptionInvoiceTools = [
|
|
|
31598
31749
|
openWorldHint: true
|
|
31599
31750
|
},
|
|
31600
31751
|
inputSchema: external_exports3.object({
|
|
31601
|
-
subscriptionInvoiceId:
|
|
31752
|
+
subscriptionInvoiceId: lsIdSchema.describe("The subscription invoice ID to refund"),
|
|
31602
31753
|
amount: external_exports3.number().int().min(1).describe("Refund amount in cents (e.g. 1000 = $10.00)")
|
|
31603
31754
|
}),
|
|
31604
31755
|
handler: async (input) => {
|
|
@@ -31627,14 +31778,14 @@ var subscriptionItemTools = [
|
|
|
31627
31778
|
openWorldHint: true
|
|
31628
31779
|
},
|
|
31629
31780
|
inputSchema: external_exports3.object({
|
|
31630
|
-
subscriptionItemId:
|
|
31781
|
+
subscriptionItemId: lsIdSchema.describe("The subscription item ID"),
|
|
31631
31782
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription,price,usage-records')")
|
|
31632
31783
|
}),
|
|
31633
31784
|
handler: getHandler("/subscription-items", "subscriptionItemId")
|
|
31634
31785
|
},
|
|
31635
31786
|
{
|
|
31636
31787
|
name: "ls_list_subscription_items",
|
|
31637
|
-
description: "List all subscription items, optionally filtered by subscription or price. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31788
|
+
description: "List all subscription items, optionally filtered by subscription or price. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: subscriptionId, priceId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31638
31789
|
annotations: {
|
|
31639
31790
|
title: "List subscription items",
|
|
31640
31791
|
readOnlyHint: true,
|
|
@@ -31643,12 +31794,13 @@ var subscriptionItemTools = [
|
|
|
31643
31794
|
openWorldHint: true
|
|
31644
31795
|
},
|
|
31645
31796
|
inputSchema: external_exports3.object({
|
|
31646
|
-
subscriptionId:
|
|
31647
|
-
priceId:
|
|
31797
|
+
subscriptionId: lsIdSchema.optional().describe("Filter by subscription ID"),
|
|
31798
|
+
priceId: lsIdSchema.optional().describe("Filter by price ID"),
|
|
31648
31799
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription,price,usage-records')"),
|
|
31649
31800
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31650
31801
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31651
31802
|
}),
|
|
31803
|
+
requiredFilters: ["subscriptionId", "priceId"],
|
|
31652
31804
|
handler: listHandler("/subscription-items", { subscriptionId: "subscription_id", priceId: "price_id" })
|
|
31653
31805
|
},
|
|
31654
31806
|
{
|
|
@@ -31662,7 +31814,7 @@ var subscriptionItemTools = [
|
|
|
31662
31814
|
openWorldHint: true
|
|
31663
31815
|
},
|
|
31664
31816
|
inputSchema: external_exports3.object({
|
|
31665
|
-
subscriptionItemId:
|
|
31817
|
+
subscriptionItemId: lsIdSchema.describe("The subscription item ID to update"),
|
|
31666
31818
|
quantity: external_exports3.number().int().min(1).describe("New quantity for the subscription item")
|
|
31667
31819
|
}),
|
|
31668
31820
|
handler: async (input) => {
|
|
@@ -31686,7 +31838,7 @@ var subscriptionItemTools = [
|
|
|
31686
31838
|
openWorldHint: true
|
|
31687
31839
|
},
|
|
31688
31840
|
inputSchema: external_exports3.object({
|
|
31689
|
-
subscriptionItemId:
|
|
31841
|
+
subscriptionItemId: lsIdSchema.describe("The subscription item ID")
|
|
31690
31842
|
}),
|
|
31691
31843
|
handler: async (input) => {
|
|
31692
31844
|
return apiGet(`/subscription-items/${encodePath(input.subscriptionItemId)}/current-usage`);
|
|
@@ -31707,7 +31859,7 @@ var subscriptionTools = [
|
|
|
31707
31859
|
openWorldHint: true
|
|
31708
31860
|
},
|
|
31709
31861
|
inputSchema: external_exports3.object({
|
|
31710
|
-
subscriptionId:
|
|
31862
|
+
subscriptionId: lsIdSchema.describe("The subscription ID"),
|
|
31711
31863
|
include: external_exports3.string().max(1e4).optional().describe(
|
|
31712
31864
|
"Comma-separated related resources to include (e.g. 'store,customer,order,order-item,product,variant,subscription-items,subscription-invoices')"
|
|
31713
31865
|
)
|
|
@@ -31725,11 +31877,11 @@ var subscriptionTools = [
|
|
|
31725
31877
|
openWorldHint: true
|
|
31726
31878
|
},
|
|
31727
31879
|
inputSchema: external_exports3.object({
|
|
31728
|
-
storeId:
|
|
31729
|
-
orderId:
|
|
31730
|
-
orderItemId:
|
|
31731
|
-
productId:
|
|
31732
|
-
variantId:
|
|
31880
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
31881
|
+
orderId: lsIdSchema.optional().describe("Filter by order ID"),
|
|
31882
|
+
orderItemId: lsIdSchema.optional().describe("Filter by order item ID"),
|
|
31883
|
+
productId: lsIdSchema.optional().describe("Filter by product ID"),
|
|
31884
|
+
variantId: lsIdSchema.optional().describe("Filter by variant ID"),
|
|
31733
31885
|
userEmail: external_exports3.string().email().max(320).optional().describe("Filter by user email"),
|
|
31734
31886
|
status: external_exports3.enum(["on_trial", "active", "paused", "past_due", "unpaid", "cancelled", "expired"]).optional().describe("Filter by subscription status"),
|
|
31735
31887
|
include: external_exports3.string().max(1e4).optional().describe(
|
|
@@ -31770,8 +31922,8 @@ var subscriptionTools = [
|
|
|
31770
31922
|
// - disableProrations toggle on plan-change behavior
|
|
31771
31923
|
isDestructive: (input) => typeof input.pause === "string" && input.pause !== "resume" || typeof input.variantId === "string",
|
|
31772
31924
|
inputSchema: external_exports3.object({
|
|
31773
|
-
subscriptionId:
|
|
31774
|
-
variantId:
|
|
31925
|
+
subscriptionId: lsIdSchema.describe("The subscription ID to update"),
|
|
31926
|
+
variantId: lsIdSchema.optional().describe("New variant ID for plan switching"),
|
|
31775
31927
|
pause: external_exports3.enum(["void", "free", "resume"]).optional().describe("Pause mode: 'void' (pause, skip billing), 'free' (pause, keep access free), or 'resume' to unpause"),
|
|
31776
31928
|
cancelled: external_exports3.literal(false).optional().describe(
|
|
31777
31929
|
"Set to false to un-cancel a subscription before it expires. To cancel, use ls_cancel_subscription instead."
|
|
@@ -31810,7 +31962,7 @@ var subscriptionTools = [
|
|
|
31810
31962
|
openWorldHint: true
|
|
31811
31963
|
},
|
|
31812
31964
|
inputSchema: external_exports3.object({
|
|
31813
|
-
subscriptionId:
|
|
31965
|
+
subscriptionId: lsIdSchema.describe("The subscription ID to cancel")
|
|
31814
31966
|
}),
|
|
31815
31967
|
handler: async (input) => {
|
|
31816
31968
|
return apiDelete(`/subscriptions/${encodePath(input.subscriptionId)}`);
|
|
@@ -31831,14 +31983,14 @@ var usageRecordTools = [
|
|
|
31831
31983
|
openWorldHint: true
|
|
31832
31984
|
},
|
|
31833
31985
|
inputSchema: external_exports3.object({
|
|
31834
|
-
usageRecordId:
|
|
31986
|
+
usageRecordId: lsIdSchema.describe("The usage record ID"),
|
|
31835
31987
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription-item')")
|
|
31836
31988
|
}),
|
|
31837
31989
|
handler: getHandler("/usage-records", "usageRecordId")
|
|
31838
31990
|
},
|
|
31839
31991
|
{
|
|
31840
31992
|
name: "ls_list_usage_records",
|
|
31841
|
-
description: "List all usage records, optionally filtered by subscription item. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31993
|
+
description: "List all usage records, optionally filtered by subscription item. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: subscriptionItemId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31842
31994
|
annotations: {
|
|
31843
31995
|
title: "List usage records",
|
|
31844
31996
|
readOnlyHint: true,
|
|
@@ -31847,11 +31999,12 @@ var usageRecordTools = [
|
|
|
31847
31999
|
openWorldHint: true
|
|
31848
32000
|
},
|
|
31849
32001
|
inputSchema: external_exports3.object({
|
|
31850
|
-
subscriptionItemId:
|
|
32002
|
+
subscriptionItemId: lsIdSchema.optional().describe("Filter by subscription item ID"),
|
|
31851
32003
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription-item')"),
|
|
31852
32004
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31853
32005
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31854
32006
|
}),
|
|
32007
|
+
requiredFilters: ["subscriptionItemId"],
|
|
31855
32008
|
handler: listHandler("/usage-records", { subscriptionItemId: "subscription_item_id" })
|
|
31856
32009
|
},
|
|
31857
32010
|
{
|
|
@@ -31868,7 +32021,7 @@ var usageRecordTools = [
|
|
|
31868
32021
|
openWorldHint: true
|
|
31869
32022
|
},
|
|
31870
32023
|
inputSchema: external_exports3.object({
|
|
31871
|
-
subscriptionItemId:
|
|
32024
|
+
subscriptionItemId: lsIdSchema.describe("The subscription item ID to report usage for"),
|
|
31872
32025
|
quantity: external_exports3.number().int().min(0).describe("The usage quantity to report"),
|
|
31873
32026
|
action: external_exports3.enum(["increment", "set"]).optional().describe("How to apply the quantity: 'increment' (add to current, default) or 'set' (replace current)")
|
|
31874
32027
|
}),
|
|
@@ -31924,14 +32077,14 @@ var variantTools = [
|
|
|
31924
32077
|
openWorldHint: true
|
|
31925
32078
|
},
|
|
31926
32079
|
inputSchema: external_exports3.object({
|
|
31927
|
-
variantId:
|
|
32080
|
+
variantId: lsIdSchema.describe("The variant ID"),
|
|
31928
32081
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'product,files')")
|
|
31929
32082
|
}),
|
|
31930
32083
|
handler: getHandler("/variants", "variantId")
|
|
31931
32084
|
},
|
|
31932
32085
|
{
|
|
31933
32086
|
name: "ls_list_variants",
|
|
31934
|
-
description: "List all variants, optionally filtered by product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
32087
|
+
description: "List all variants, optionally filtered by product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: productId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31935
32088
|
annotations: {
|
|
31936
32089
|
title: "List variants",
|
|
31937
32090
|
readOnlyHint: true,
|
|
@@ -31940,11 +32093,12 @@ var variantTools = [
|
|
|
31940
32093
|
openWorldHint: true
|
|
31941
32094
|
},
|
|
31942
32095
|
inputSchema: external_exports3.object({
|
|
31943
|
-
productId:
|
|
32096
|
+
productId: lsIdSchema.optional().describe("Filter by product ID"),
|
|
31944
32097
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'product,files')"),
|
|
31945
32098
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31946
32099
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31947
32100
|
}),
|
|
32101
|
+
requiredFilters: ["productId"],
|
|
31948
32102
|
handler: listHandler("/variants", { productId: "product_id" })
|
|
31949
32103
|
}
|
|
31950
32104
|
];
|
|
@@ -31962,7 +32116,7 @@ var webhookTools = [
|
|
|
31962
32116
|
openWorldHint: true
|
|
31963
32117
|
},
|
|
31964
32118
|
inputSchema: external_exports3.object({
|
|
31965
|
-
webhookId:
|
|
32119
|
+
webhookId: lsIdSchema.describe("The webhook ID"),
|
|
31966
32120
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store')")
|
|
31967
32121
|
}),
|
|
31968
32122
|
handler: getHandler("/webhooks", "webhookId")
|
|
@@ -31978,7 +32132,7 @@ var webhookTools = [
|
|
|
31978
32132
|
openWorldHint: true
|
|
31979
32133
|
},
|
|
31980
32134
|
inputSchema: external_exports3.object({
|
|
31981
|
-
storeId:
|
|
32135
|
+
storeId: lsIdSchema.optional().describe("Filter by store ID"),
|
|
31982
32136
|
include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store')"),
|
|
31983
32137
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31984
32138
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
@@ -31996,7 +32150,7 @@ var webhookTools = [
|
|
|
31996
32150
|
openWorldHint: true
|
|
31997
32151
|
},
|
|
31998
32152
|
inputSchema: external_exports3.object({
|
|
31999
|
-
storeId:
|
|
32153
|
+
storeId: lsIdSchema.describe("The store ID"),
|
|
32000
32154
|
url: external_exports3.string().max(1e4).describe("The URL to send webhook events to"),
|
|
32001
32155
|
events: external_exports3.array(external_exports3.string()).describe(
|
|
32002
32156
|
"Event types to subscribe to (e.g. ['order_created', 'subscription_created', 'subscription_updated', 'subscription_cancelled', 'subscription_payment_success', 'subscription_payment_failed', 'license_key_created'])"
|
|
@@ -32030,7 +32184,7 @@ var webhookTools = [
|
|
|
32030
32184
|
openWorldHint: true
|
|
32031
32185
|
},
|
|
32032
32186
|
inputSchema: external_exports3.object({
|
|
32033
|
-
webhookId:
|
|
32187
|
+
webhookId: lsIdSchema.describe("The webhook ID to update"),
|
|
32034
32188
|
url: external_exports3.string().max(1e4).optional().describe("New URL to send webhook events to"),
|
|
32035
32189
|
events: external_exports3.array(external_exports3.string()).optional().describe("Updated list of event types to subscribe to"),
|
|
32036
32190
|
secret: external_exports3.string().min(6).max(40).optional().describe("New signing secret")
|
|
@@ -32060,7 +32214,7 @@ var webhookTools = [
|
|
|
32060
32214
|
openWorldHint: true
|
|
32061
32215
|
},
|
|
32062
32216
|
inputSchema: external_exports3.object({
|
|
32063
|
-
webhookId:
|
|
32217
|
+
webhookId: lsIdSchema.describe("The webhook ID to delete")
|
|
32064
32218
|
}),
|
|
32065
32219
|
handler: async (input) => {
|
|
32066
32220
|
return apiDelete(`/webhooks/${encodePath(input.webhookId)}`);
|
|
@@ -32069,7 +32223,7 @@ var webhookTools = [
|
|
|
32069
32223
|
];
|
|
32070
32224
|
|
|
32071
32225
|
// src/index.ts
|
|
32072
|
-
var version2 = true ? "0.
|
|
32226
|
+
var version2 = true ? "0.7.1" : (await null).createRequire(import.meta.url)("../package.json").version;
|
|
32073
32227
|
var subcommand = process.argv[2];
|
|
32074
32228
|
if (subcommand === "version" || subcommand === "--version") {
|
|
32075
32229
|
console.log(version2);
|
|
@@ -32103,7 +32257,6 @@ var server = new McpServer({
|
|
|
32103
32257
|
version: version2
|
|
32104
32258
|
});
|
|
32105
32259
|
for (const tool of allTools) {
|
|
32106
|
-
const toolAcceptsStoreId = "storeId" in tool.inputSchema.shape;
|
|
32107
32260
|
server.tool(
|
|
32108
32261
|
tool.name,
|
|
32109
32262
|
tool.description,
|
|
@@ -32114,7 +32267,7 @@ for (const tool of allTools) {
|
|
|
32114
32267
|
const start = Date.now();
|
|
32115
32268
|
try {
|
|
32116
32269
|
if (isDestructive) checkDestructiveRateLimit();
|
|
32117
|
-
checkStoreScopedToolInput(
|
|
32270
|
+
checkStoreScopedToolInput(tool, input);
|
|
32118
32271
|
const result = await tool.handler(input);
|
|
32119
32272
|
const response = result;
|
|
32120
32273
|
const latency_ms = Date.now() - start;
|
|
@@ -32126,7 +32279,7 @@ for (const tool of allTools) {
|
|
|
32126
32279
|
request_id: response.requestId,
|
|
32127
32280
|
error: response.ok ? void 0 : response.error,
|
|
32128
32281
|
audit: isDestructive ? true : void 0,
|
|
32129
|
-
inputs: isDestructive ? input : void 0
|
|
32282
|
+
inputs: isDestructive ? redactSecrets(input) : void 0
|
|
32130
32283
|
});
|
|
32131
32284
|
if (!response.ok) {
|
|
32132
32285
|
return {
|
|
@@ -32153,7 +32306,7 @@ for (const tool of allTools) {
|
|
|
32153
32306
|
latency_ms,
|
|
32154
32307
|
error: message,
|
|
32155
32308
|
audit: isDestructive ? true : void 0,
|
|
32156
|
-
inputs: isDestructive ? input : void 0
|
|
32309
|
+
inputs: isDestructive ? redactSecrets(input) : void 0
|
|
32157
32310
|
});
|
|
32158
32311
|
return {
|
|
32159
32312
|
content: [{ type: "text", text: `Error: ${message}` }],
|