@yawlabs/lemonsqueezy-mcp 0.10.6 → 0.10.7
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/CHANGELOG.md +12 -1
- package/dist/index.js +47 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@yawlabs/lemonsqueezy-mcp` are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and versioning follows [SEMVER.md](./SEMVER.md).
|
|
4
4
|
|
|
5
|
+
## [0.10.7] -- 2026-05-16
|
|
6
|
+
|
|
7
|
+
### Security
|
|
8
|
+
|
|
9
|
+
- **Allowlist-bypass surface closed at the test layer.** `checkStoreScopedToolInput` in `src/wrapper.ts` enforces `LEMONSQUEEZY_ALLOWED_STORE_IDS` by reading the literal input field name `storeId` from the tool's Zod shape. Today every list tool that filters by store happens to use that name, but the convention wasn't asserted anywhere -- a future tool whose filterMap mapped a differently-named input (e.g. `store`) to `filter[store_id]` would silently bypass the allowlist. `src/api.ts` `listHandler` now exposes its `filterMap` on the returned handler, and `src/tools/tools.test.ts` adds an invariant that fails CI for any drift between the filter key (`store_id`) and the input field name (`storeId`).
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **`wrapper.ts` skips the success/error entry literal when no consumer wants it.** A non-destructive read at `LEMONSQUEEZY_LOG` unset (i.e. "off") previously built a full audit entry on every call, then `logEvent` discarded it inside its level check. Now the wrapper consults `wouldLogToolCall({ isDestructive, isError })` -- a new export from `src/logger.ts` -- before allocating. Destructive calls always build the entry because the audit-buffer push is independent of the log level. No observable behavior change; saves a small object literal per non-destructive read on the most common configuration.
|
|
14
|
+
|
|
5
15
|
## [0.10.6] -- 2026-05-16
|
|
6
16
|
|
|
7
17
|
### Security
|
|
@@ -333,7 +343,8 @@ Hardening pass for unattended automation against live billing flows.
|
|
|
333
343
|
|
|
334
344
|
Initial release. 59 tools covering all 17 LemonSqueezy API resources.
|
|
335
345
|
|
|
336
|
-
[Unreleased]: https://github.com/YawLabs/lemonsqueezy-mcp/compare/v0.10.
|
|
346
|
+
[Unreleased]: https://github.com/YawLabs/lemonsqueezy-mcp/compare/v0.10.7...HEAD
|
|
347
|
+
[0.10.7]: https://github.com/YawLabs/lemonsqueezy-mcp/compare/v0.10.6...v0.10.7
|
|
337
348
|
[0.10.6]: https://github.com/YawLabs/lemonsqueezy-mcp/compare/v0.10.5...v0.10.6
|
|
338
349
|
[0.10.5]: https://github.com/YawLabs/lemonsqueezy-mcp/compare/v0.10.4...v0.10.5
|
|
339
350
|
[0.10.4]: https://github.com/YawLabs/lemonsqueezy-mcp/compare/v0.10.3...v0.10.4
|
package/dist/index.js
CHANGED
|
@@ -30410,6 +30410,19 @@ function shouldLog(entry, level) {
|
|
|
30410
30410
|
return isErrorEntry(entry);
|
|
30411
30411
|
}
|
|
30412
30412
|
}
|
|
30413
|
+
function wouldLogToolCall(opts) {
|
|
30414
|
+
const level = getLogLevel();
|
|
30415
|
+
switch (level) {
|
|
30416
|
+
case "off":
|
|
30417
|
+
return false;
|
|
30418
|
+
case "all":
|
|
30419
|
+
return true;
|
|
30420
|
+
case "audit":
|
|
30421
|
+
return opts.isDestructive || opts.isError;
|
|
30422
|
+
case "error":
|
|
30423
|
+
return opts.isError;
|
|
30424
|
+
}
|
|
30425
|
+
}
|
|
30413
30426
|
function safeString(value) {
|
|
30414
30427
|
if (value === void 0) return void 0;
|
|
30415
30428
|
if (typeof value === "string") return value;
|
|
@@ -30886,7 +30899,7 @@ function getHandler(endpoint, idField) {
|
|
|
30886
30899
|
};
|
|
30887
30900
|
}
|
|
30888
30901
|
function listHandler(endpoint, filterMap = {}) {
|
|
30889
|
-
|
|
30902
|
+
const handler = async (input) => {
|
|
30890
30903
|
const filter = {};
|
|
30891
30904
|
for (const [inputKey, apiKey] of Object.entries(filterMap)) {
|
|
30892
30905
|
const val = input[inputKey];
|
|
@@ -30899,6 +30912,7 @@ function listHandler(endpoint, filterMap = {}) {
|
|
|
30899
30912
|
});
|
|
30900
30913
|
return apiGet(`${endpoint}${query}`);
|
|
30901
30914
|
};
|
|
30915
|
+
return Object.assign(handler, { filterMap });
|
|
30902
30916
|
}
|
|
30903
30917
|
async function apiGet(path) {
|
|
30904
30918
|
return apiRequest("GET", path);
|
|
@@ -32719,19 +32733,22 @@ function createToolHandler(tool) {
|
|
|
32719
32733
|
checkStoreScopedToolInput(toolAsRecord, inputAsRecord);
|
|
32720
32734
|
const response = await tool.handler(input);
|
|
32721
32735
|
const latency_ms = Date.now() - start;
|
|
32722
|
-
const
|
|
32723
|
-
|
|
32724
|
-
|
|
32725
|
-
|
|
32726
|
-
|
|
32727
|
-
|
|
32728
|
-
|
|
32729
|
-
|
|
32730
|
-
|
|
32731
|
-
|
|
32732
|
-
|
|
32733
|
-
|
|
32734
|
-
|
|
32736
|
+
const wouldLog = wouldLogToolCall({ isDestructive, isError: !response.ok });
|
|
32737
|
+
if (wouldLog || isDestructive) {
|
|
32738
|
+
const successEntry = {
|
|
32739
|
+
event: "tool_call",
|
|
32740
|
+
tool: tool.name,
|
|
32741
|
+
status: response.ok ? "ok" : "error",
|
|
32742
|
+
latency_ms,
|
|
32743
|
+
request_id: response.requestId,
|
|
32744
|
+
error: response.ok ? void 0 : response.error,
|
|
32745
|
+
audit: isDestructive ? true : void 0,
|
|
32746
|
+
inputs: isDestructive ? redactSecrets(input) : void 0
|
|
32747
|
+
};
|
|
32748
|
+
if (wouldLog) logEvent(successEntry);
|
|
32749
|
+
if (isDestructive) {
|
|
32750
|
+
pushAuditEntry({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...successEntry });
|
|
32751
|
+
}
|
|
32735
32752
|
}
|
|
32736
32753
|
if (!response.ok) {
|
|
32737
32754
|
return {
|
|
@@ -32751,18 +32768,21 @@ function createToolHandler(tool) {
|
|
|
32751
32768
|
} catch (err) {
|
|
32752
32769
|
const message = err instanceof Error ? err.message : String(err);
|
|
32753
32770
|
const latency_ms = Date.now() - start;
|
|
32754
|
-
const
|
|
32755
|
-
|
|
32756
|
-
|
|
32757
|
-
|
|
32758
|
-
|
|
32759
|
-
|
|
32760
|
-
|
|
32761
|
-
|
|
32762
|
-
|
|
32763
|
-
|
|
32764
|
-
|
|
32765
|
-
|
|
32771
|
+
const wouldLog = wouldLogToolCall({ isDestructive, isError: true });
|
|
32772
|
+
if (wouldLog || isDestructive) {
|
|
32773
|
+
const errorEntry = {
|
|
32774
|
+
event: "tool_call",
|
|
32775
|
+
tool: tool.name,
|
|
32776
|
+
status: err instanceof GuardrailError ? "guardrail_block" : "exception",
|
|
32777
|
+
latency_ms,
|
|
32778
|
+
error: message,
|
|
32779
|
+
audit: isDestructive ? true : void 0,
|
|
32780
|
+
inputs: isDestructive ? redactSecrets(input) : void 0
|
|
32781
|
+
};
|
|
32782
|
+
if (wouldLog) logEvent(errorEntry);
|
|
32783
|
+
if (isDestructive) {
|
|
32784
|
+
pushAuditEntry({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...errorEntry });
|
|
32785
|
+
}
|
|
32766
32786
|
}
|
|
32767
32787
|
return {
|
|
32768
32788
|
content: [{ type: "text", text: `Error: ${message}` }],
|
|
@@ -32786,7 +32806,7 @@ function readAuditLogResource(uri) {
|
|
|
32786
32806
|
}
|
|
32787
32807
|
|
|
32788
32808
|
// src/index.ts
|
|
32789
|
-
var version2 = true ? "0.10.
|
|
32809
|
+
var version2 = true ? "0.10.7" : (await null).createRequire(import.meta.url)("../package.json").version;
|
|
32790
32810
|
var subcommand = process.argv[2];
|
|
32791
32811
|
if (subcommand === "version" || subcommand === "--version") {
|
|
32792
32812
|
console.log(version2);
|
package/package.json
CHANGED