@thenavidm/slipway 0.1.10 → 0.1.11

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 CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  What changed in Slipway, newest first.
4
4
 
5
+ ## 0.1.11, 2026-10-05: what WordPress needed
6
+
7
+ - **Records no longer advertise `propertyNames`.** Zod 4 gives every `z.record` `propertyNames: { type: "string" }`, which every JSON object key already is, and the Zod 3 converters never wrote it. Slipway leaves it out of what clients receive, as it does the safe-integer bounds, and validation still runs on the schema itself. Each one cost 8 tokens; WordPress has nine. An argument that happens to be named `propertyNames` is a name, so it stays.
8
+
5
9
  ## 0.1.10, 2026-10-05: what TikTok needed
6
10
 
7
11
  - **`destructiveOff: "hide"`: a server can take its irreversible tools off the list when they are off.** By default `<PREFIX>_ALLOW_DESTRUCTIVE=0` keeps them listed and refuses each call. With `defaults: { destructiveOff: "hide" }` they leave the MCP tool list and the command list, as read-only mode does with every write, and calling one anyway is refused with the setting to unset. TikTok 1.1 hid its publishing tools this way, and keeps doing so.
package/README.md CHANGED
@@ -580,7 +580,9 @@ See [CHANGELOG.md](CHANGELOG.md).
580
580
  | [Substack](https://github.com/thenavidm/substack-mcp-cli) | [`@thenavidm/substack-mcp-cli`](https://www.npmjs.com/package/@thenavidm/substack-mcp-cli) 3.0.0 | Drafts, publishing and scheduling, Notes, subscribers, analytics, tags, comments and researching other publications |
581
581
  | [Teachable](https://github.com/thenavidm/teachable-mcp-cli) | [`@thenavidm/teachable-mcp-cli`](https://www.npmjs.com/package/@thenavidm/teachable-mcp-cli) 3.0.0 | Courses, users, enrollments, pricing, coupons and transactions |
582
582
  | [Threads](https://github.com/thenavidm/threads-mcp-cli) | [`@thenavidm/threads-mcp-cli`](https://www.npmjs.com/package/@thenavidm/threads-mcp-cli) 2.0.0 | Posting, threads, carousels, replies and reply approvals, insights and keyword search |
583
+ | [TikTok](https://github.com/thenavidm/tiktok-mcp-cli) | [`@thenavidm/tiktok-mcp-cli`](https://www.npmjs.com/package/@thenavidm/tiktok-mcp-cli) 2.0.0 | Your own account's profile and videos, ranked by any metric, posting and drafts, through TikTok's official API |
583
584
  | [ThriveCart](https://github.com/thenavidm/thrivecart-mcp-cli) | [`@thenavidm/thrivecart-mcp-cli`](https://www.npmjs.com/package/@thenavidm/thrivecart-mcp-cli) 3.0.0 | Products and pricing, transactions and revenue, customers, subscriptions and affiliates, across several carts |
585
+ | [YouTube](https://github.com/thenavidm/youtube-mcp-cli) | [`@thenavidm/youtube-mcp-cli`](https://www.npmjs.com/package/@thenavidm/youtube-mcp-cli) 3.0.0 | Transcripts of any public video, channel research against each channel's own median, and your own channels' videos, comments and analytics |
584
586
 
585
587
  Each server was measured against its previous release before it moved: startup, what a client receives, CLI exit codes, and tokens in Claude Code and Codex. Its README has the numbers.
586
588
 
package/dist/schema.js CHANGED
@@ -83,25 +83,36 @@ export const CONTROL_NAMES = ["confirm", "wait_seconds"];
83
83
  export const CONFIRM_DESCRIPTION = "Set true only when the user asked for exactly this action.";
84
84
  /** The schema already carries the range and the default, so the words only say what the number is for. */
85
85
  export const WAIT_DESCRIPTION = "Seconds to wait for the job to finish before returning it to check later.";
86
+ /** Keywords whose keys are names the author chose, not keywords. */
87
+ const NAMED = new Set(["properties", "patternProperties", "$defs", "definitions", "dependentSchemas"]);
86
88
  /**
87
89
  * Zod 4 gives every whole number the safe-integer bounds, `maximum:
88
- * 9007199254740991` and its negative, unless the schema sets its own. They say
89
- * nothing a client can use, so they are left out of what it receives.
90
- * Validation still runs on the schema itself.
90
+ * 9007199254740991` and its negative, unless the schema sets its own, and
91
+ * every record `propertyNames: { type: "string" }`, which every JSON object key
92
+ * already is. They say nothing a client can use, so they are left out of what
93
+ * it receives. Validation still runs on the schema itself. An argument that
94
+ * happens to be named `propertyNames` or `maximum` is a name, so it stays.
91
95
  */
92
- function withoutSafeIntegerBounds(node) {
96
+ function withoutNoise(node, named = false) {
93
97
  if (Array.isArray(node))
94
- return node.map(withoutSafeIntegerBounds);
98
+ return node.map((item) => withoutNoise(item));
95
99
  if (node === null || typeof node !== "object")
96
100
  return node;
97
101
  const out = {};
98
102
  for (const [key, value] of Object.entries(node)) {
99
- if ((key === "maximum" && value === Number.MAX_SAFE_INTEGER) || (key === "minimum" && value === Number.MIN_SAFE_INTEGER))
100
- continue;
101
- out[key] = withoutSafeIntegerBounds(value);
103
+ if (!named) {
104
+ if ((key === "maximum" && value === Number.MAX_SAFE_INTEGER) || (key === "minimum" && value === Number.MIN_SAFE_INTEGER))
105
+ continue;
106
+ if (key === "propertyNames" && isPlainString(value))
107
+ continue;
108
+ }
109
+ out[key] = withoutNoise(value, !named && NAMED.has(key));
102
110
  }
103
111
  return out;
104
112
  }
113
+ function isPlainString(value) {
114
+ return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 1 && value.type === "string";
115
+ }
105
116
  /**
106
117
  * A schema as clients receive it, without the `$schema` line that names its
107
118
  * dialect. A client reads JSON Schema 2020-12 when no dialect is named, so
@@ -111,7 +122,7 @@ export function advertised(schema) {
111
122
  const std = schema["~standard"];
112
123
  const plain = (json) => {
113
124
  const { $schema: _dialect, ...rest } = json;
114
- return withoutSafeIntegerBounds(rest);
125
+ return withoutNoise(rest);
115
126
  };
116
127
  return {
117
128
  "~standard": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thenavidm/slipway",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Slipway, the TypeScript framework for MCP servers and agent-native CLIs. One tool definition ships an MCP server and a CLI, with write safety, typed results and release checks built in.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",