@jaypie/mcp 0.2.1 → 0.2.2

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/dist/index.js CHANGED
@@ -797,7 +797,7 @@ async function searchDatadogRum(credentials, options = {}, logger = nullLogger)
797
797
  });
798
798
  }
799
799
 
800
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.1#22724b60"
800
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.2.2#fd3043b3"
801
801
  ;
802
802
  const __filename$1 = fileURLToPath(import.meta.url);
803
803
  const __dirname$1 = path.dirname(__filename$1);
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "https://github.com/finlaysonstudio/jaypie"
7
+ "url": "git+https://github.com/finlaysonstudio/jaypie.git"
8
8
  },
9
9
  "license": "MIT",
10
10
  "author": "Finlayson Studio",
@@ -49,6 +49,5 @@
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"
52
- },
53
- "gitHead": "22724b6031f0e737ba7fa4acf7df7c2391e2e2f4"
52
+ }
54
53
  }
@@ -0,0 +1,451 @@
1
+ ---
2
+ description: Complete guide to using Jaypie Vocabulary for type coercion, service handlers, and Commander CLI integration
3
+ ---
4
+
5
+ # Jaypie Vocabulary Package
6
+
7
+ Jaypie Vocabulary (`@jaypie/vocabulary`) provides type coercion utilities and service handler patterns for consistent input handling across Jaypie applications. It includes adapters for integrating service handlers with Commander.js CLIs.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @jaypie/vocabulary
13
+ # For CLI integration:
14
+ npm install commander
15
+ ```
16
+
17
+ ## Core Concepts
18
+
19
+ ### Design Philosophy
20
+
21
+ Vocabulary follows the "Fabric" philosophy:
22
+ - **Smooth, pliable** - Things that feel right should work
23
+ - **Catch bad passes** - Invalid inputs throw clear errors
24
+
25
+ This means `"true"` works where `true` is expected, `"42"` works where `42` is expected, and invalid conversions fail fast with `BadRequestError`.
26
+
27
+ ## serviceHandler
28
+
29
+ Factory function that creates validated service endpoints with automatic type coercion.
30
+
31
+ ### Basic Usage
32
+
33
+ ```typescript
34
+ import { serviceHandler } from "@jaypie/vocabulary";
35
+
36
+ const divisionHandler = serviceHandler({
37
+ alias: "division",
38
+ description: "Divides two numbers",
39
+ input: {
40
+ numerator: {
41
+ type: Number,
42
+ default: 12,
43
+ description: "Number on top",
44
+ },
45
+ denominator: {
46
+ type: Number,
47
+ default: 3,
48
+ description: "Number on bottom",
49
+ validate: (value) => value !== 0,
50
+ },
51
+ },
52
+ service: ({ numerator, denominator }) => numerator / denominator,
53
+ });
54
+
55
+ await divisionHandler(); // → 4
56
+ await divisionHandler({ numerator: 24 }); // → 8
57
+ await divisionHandler({ numerator: "14", denominator: "7" }); // → 2 (coerced)
58
+ await divisionHandler('{"numerator": "18"}'); // → 6 (JSON parsed)
59
+ ```
60
+
61
+ ### Handler Properties
62
+
63
+ Config properties are attached directly to the handler for introspection:
64
+
65
+ ```typescript
66
+ const handler = serviceHandler({
67
+ alias: "greet",
68
+ description: "Greet a user",
69
+ input: { name: { type: String } },
70
+ service: ({ name }) => `Hello, ${name}!`,
71
+ });
72
+
73
+ handler.alias; // "greet"
74
+ handler.description; // "Greet a user"
75
+ handler.input; // { name: { type: String } }
76
+ ```
77
+
78
+ ### Input Field Definition
79
+
80
+ | Property | Type | Description |
81
+ |----------|------|-------------|
82
+ | `type` | `CoercionType` | Required. The target type for coercion |
83
+ | `default` | `unknown` | Default value if not provided |
84
+ | `description` | `string` | Field description (used in CLI help) |
85
+ | `required` | `boolean` | Whether field is required (default: true unless default set) |
86
+ | `validate` | `function \| RegExp \| array` | Validation after coercion |
87
+ | `flag` | `string` | Override long flag name for Commander.js |
88
+ | `letter` | `string` | Short switch letter for Commander.js |
89
+
90
+ ### Validation-Only Mode
91
+
92
+ When no `service` function is provided, the handler returns the processed input:
93
+
94
+ ```typescript
95
+ const validateUser = serviceHandler({
96
+ input: {
97
+ age: { type: Number, validate: (v) => v >= 18 },
98
+ email: { type: /^[^@]+@[^@]+\.[^@]+$/ },
99
+ role: { type: ["admin", "user", "guest"], default: "user" },
100
+ },
101
+ });
102
+
103
+ await validateUser({ age: "25", email: "bob@example.com" });
104
+ // → { age: 25, email: "bob@example.com", role: "user" }
105
+ ```
106
+
107
+ ## Type Coercion
108
+
109
+ ### Supported Types
110
+
111
+ | Type | Aliases | Description |
112
+ |------|---------|-------------|
113
+ | `String` | `"string"`, `""` | String coercion |
114
+ | `Number` | `"number"` | Number coercion |
115
+ | `Boolean` | `"boolean"` | Boolean coercion |
116
+ | `Array` | `"array"`, `[]` | Array coercion |
117
+ | `Object` | `"object"`, `{}` | Object coercion |
118
+ | `[String]` | `[""]` | Typed array of strings |
119
+ | `[Number]` | - | Typed array of numbers |
120
+ | `[Boolean]` | - | Typed array of booleans |
121
+ | `[Object]` | `[{}]` | Typed array of objects |
122
+ | `/regex/` | - | String with regex validation |
123
+ | `["a", "b"]` | - | Validated string (must match) |
124
+ | `[1, 2, 3]` | - | Validated number (must match) |
125
+
126
+ ### Coercion Examples
127
+
128
+ ```typescript
129
+ import { coerce } from "@jaypie/vocabulary";
130
+
131
+ // Boolean coercion
132
+ coerce("true", Boolean); // → true
133
+ coerce("false", Boolean); // → false
134
+ coerce(1, Boolean); // → true
135
+ coerce(0, Boolean); // → false
136
+
137
+ // Number coercion
138
+ coerce("42", Number); // → 42
139
+ coerce("true", Number); // → 1
140
+ coerce("false", Number); // → 0
141
+
142
+ // String coercion
143
+ coerce(true, String); // → "true"
144
+ coerce(42, String); // → "42"
145
+
146
+ // Array coercion
147
+ coerce("1,2,3", [Number]); // → [1, 2, 3]
148
+ coerce("a\tb\tc", [String]); // → ["a", "b", "c"]
149
+ coerce([1, 2], [String]); // → ["1", "2"]
150
+
151
+ // Unwrapping
152
+ coerce({ value: "42" }, Number); // → 42
153
+ coerce(["true"], Boolean); // → true
154
+ coerce('{"value": 5}', Number); // → 5
155
+ ```
156
+
157
+ ### RegExp Type Shorthand
158
+
159
+ A bare RegExp coerces to String and validates:
160
+
161
+ ```typescript
162
+ const handler = serviceHandler({
163
+ input: {
164
+ email: { type: /^[^@]+@[^@]+\.[^@]+$/ },
165
+ },
166
+ service: ({ email }) => email,
167
+ });
168
+
169
+ await handler({ email: "bob@example.com" }); // ✓
170
+ await handler({ email: "invalid" }); // ✗ BadRequestError
171
+ ```
172
+
173
+ ### Validated Type Shorthand
174
+
175
+ Arrays of literals validate against allowed values:
176
+
177
+ ```typescript
178
+ // String validation
179
+ input: {
180
+ currency: { type: ["usd", "eur", "gbp"] }, // Must be one of these
181
+ pattern: { type: [/^test-/, "special"] }, // Matches regex OR equals "special"
182
+ }
183
+
184
+ // Number validation
185
+ input: {
186
+ priority: { type: [1, 2, 3, 4, 5] }, // Must be 1-5
187
+ }
188
+ ```
189
+
190
+ ## Commander.js Integration
191
+
192
+ ### registerServiceCommand (Recommended)
193
+
194
+ The simplest way to register a service handler as a Commander command:
195
+
196
+ ```typescript
197
+ import { Command } from "commander";
198
+ import { serviceHandler } from "@jaypie/vocabulary";
199
+ import { registerServiceCommand } from "@jaypie/vocabulary/commander";
200
+
201
+ const handler = serviceHandler({
202
+ alias: "greet",
203
+ description: "Greet a user",
204
+ input: {
205
+ userName: { type: String, flag: "user", letter: "u" },
206
+ loud: { type: Boolean, letter: "l", default: false },
207
+ },
208
+ service: ({ loud, userName }) => {
209
+ const greeting = `Hello, ${userName}!`;
210
+ console.log(loud ? greeting.toUpperCase() : greeting);
211
+ },
212
+ });
213
+
214
+ const program = new Command();
215
+ registerServiceCommand({ handler, program });
216
+ program.parse();
217
+ // Usage: greet --user Alice -l
218
+ // Output: HELLO, ALICE!
219
+ ```
220
+
221
+ ### registerServiceCommand Options
222
+
223
+ | Option | Type | Description |
224
+ |--------|------|-------------|
225
+ | `handler` | `ServiceHandlerFunction` | Required. The service handler |
226
+ | `program` | `Command` | Required. Commander program or command |
227
+ | `name` | `string` | Override command name (default: handler.alias) |
228
+ | `description` | `string` | Override description (default: handler.description) |
229
+ | `exclude` | `string[]` | Field names to exclude from options |
230
+ | `overrides` | `Record<string, override>` | Per-field option overrides |
231
+
232
+ ### Input Flag and Letter Properties
233
+
234
+ Define CLI flags directly in input definitions:
235
+
236
+ ```typescript
237
+ input: {
238
+ userName: {
239
+ type: String,
240
+ flag: "user", // Long flag: --user (instead of --user-name)
241
+ letter: "u", // Short flag: -u
242
+ description: "User name to greet",
243
+ },
244
+ verbose: {
245
+ type: Boolean,
246
+ letter: "v", // -v
247
+ },
248
+ }
249
+ // Generates: --user <userName>, -u and --verbose, -v
250
+ ```
251
+
252
+ ### Manual Integration
253
+
254
+ For more control, use `createCommanderOptions` and `parseCommanderOptions`:
255
+
256
+ ```typescript
257
+ import { Command } from "commander";
258
+ import { serviceHandler } from "@jaypie/vocabulary";
259
+ import {
260
+ createCommanderOptions,
261
+ parseCommanderOptions,
262
+ } from "@jaypie/vocabulary/commander";
263
+
264
+ const handler = serviceHandler({
265
+ input: {
266
+ userName: { type: String, description: "User name" },
267
+ maxRetries: { type: Number, default: 3 },
268
+ verbose: { type: Boolean },
269
+ },
270
+ service: (input) => console.log(input),
271
+ });
272
+
273
+ const program = new Command();
274
+
275
+ // Create options from handler input
276
+ const { options } = createCommanderOptions(handler.input, {
277
+ exclude: ["internalField"],
278
+ overrides: {
279
+ userName: { short: "u", description: "Override description" },
280
+ },
281
+ });
282
+ options.forEach((opt) => program.addOption(opt));
283
+
284
+ // Wire up action
285
+ program.action(async (opts) => {
286
+ const input = parseCommanderOptions(opts, { input: handler.input });
287
+ await handler(input);
288
+ });
289
+
290
+ program.parse();
291
+ ```
292
+
293
+ ### Boolean Flag Behavior
294
+
295
+ Commander.js automatically handles boolean flags:
296
+ - `--verbose` sets to `true`
297
+ - `--no-verbose` sets to `false` (for flags with `default: true`)
298
+
299
+ ## Complete CLI Example
300
+
301
+ ```typescript
302
+ // src/commands/evaluate.ts
303
+ import { Command } from "commander";
304
+ import { serviceHandler } from "@jaypie/vocabulary";
305
+ import { registerServiceCommand } from "@jaypie/vocabulary/commander";
306
+
307
+ export const evaluateHandler = serviceHandler({
308
+ alias: "evaluate",
309
+ description: "Run an evaluation job",
310
+ input: {
311
+ jobId: {
312
+ type: String,
313
+ flag: "job",
314
+ letter: "j",
315
+ description: "Job identifier",
316
+ },
317
+ priority: {
318
+ type: [1, 2, 3, 4, 5],
319
+ default: 3,
320
+ letter: "p",
321
+ description: "Job priority (1-5)",
322
+ },
323
+ tags: {
324
+ type: [String],
325
+ letter: "t",
326
+ required: false,
327
+ description: "Tags to apply",
328
+ },
329
+ dryRun: {
330
+ type: Boolean,
331
+ letter: "d",
332
+ default: false,
333
+ description: "Run without executing",
334
+ },
335
+ },
336
+ service: async ({ dryRun, jobId, priority, tags }) => {
337
+ console.log(`Running job ${jobId} with priority ${priority}`);
338
+ if (tags?.length) console.log(`Tags: ${tags.join(", ")}`);
339
+ if (dryRun) {
340
+ console.log("(dry run - no changes made)");
341
+ return;
342
+ }
343
+ // Execute job...
344
+ },
345
+ });
346
+
347
+ export function evaluateCommand(program: Command): Command {
348
+ registerServiceCommand({ handler: evaluateHandler, program });
349
+ return program;
350
+ }
351
+ ```
352
+
353
+ Usage:
354
+ ```bash
355
+ # Required job, default priority
356
+ cli evaluate --job abc123
357
+
358
+ # With all options
359
+ cli evaluate -j abc123 -p 1 -t urgent -t critical --dry-run
360
+
361
+ # Help
362
+ cli evaluate --help
363
+ ```
364
+
365
+ ## TypeScript Types
366
+
367
+ ```typescript
368
+ import type {
369
+ // Coercion types
370
+ CoercionType,
371
+ ScalarType,
372
+ CompositeType,
373
+ TypedArrayType,
374
+ ValidatedStringType,
375
+ ValidatedNumberType,
376
+ RegExpType,
377
+ ArrayElementType,
378
+
379
+ // Service handler types
380
+ InputFieldDefinition,
381
+ ValidateFunction,
382
+ ServiceFunction,
383
+ ServiceHandlerConfig,
384
+ ServiceHandlerFunction,
385
+ } from "@jaypie/vocabulary";
386
+
387
+ import type {
388
+ // Commander adapter types
389
+ CommanderOptionOverride,
390
+ CreateCommanderOptionsConfig,
391
+ CreateCommanderOptionsResult,
392
+ ParseCommanderOptionsConfig,
393
+ RegisterServiceCommandConfig,
394
+ RegisterServiceCommandResult,
395
+ } from "@jaypie/vocabulary/commander";
396
+ ```
397
+
398
+ ## Exports
399
+
400
+ ### Main Export (`@jaypie/vocabulary`)
401
+
402
+ ```typescript
403
+ // Coercion functions
404
+ export {
405
+ coerce,
406
+ coerceFromArray,
407
+ coerceFromObject,
408
+ coerceToArray,
409
+ coerceToBoolean,
410
+ coerceToNumber,
411
+ coerceToObject,
412
+ coerceToString,
413
+ } from "./coerce.js";
414
+
415
+ // Service Handler
416
+ export { serviceHandler } from "./serviceHandler.js";
417
+
418
+ // Commander namespace
419
+ export * as commander from "./commander/index.js";
420
+
421
+ // Version
422
+ export const VOCABULARY_VERSION: string;
423
+ ```
424
+
425
+ ### Commander Export (`@jaypie/vocabulary/commander`)
426
+
427
+ ```typescript
428
+ export { createCommanderOptions } from "./createCommanderOptions.js";
429
+ export { parseCommanderOptions } from "./parseCommanderOptions.js";
430
+ export { registerServiceCommand } from "./registerServiceCommand.js";
431
+ ```
432
+
433
+ ## Error Handling
434
+
435
+ Invalid coercions throw `BadRequestError` from `@jaypie/errors`:
436
+
437
+ ```typescript
438
+ import { BadRequestError } from "@jaypie/errors";
439
+
440
+ // These throw BadRequestError:
441
+ await handler({ numerator: "not-a-number" }); // Cannot coerce to Number
442
+ await handler({ priority: 10 }); // Validation fails (not in [1,2,3,4,5])
443
+ await handler({}); // Missing required field
444
+ ```
445
+
446
+ ## Integration with Other Packages
447
+
448
+ Vocabulary is designed to be consumed by:
449
+ - **`@jaypie/lambda`** - Lambda handler input processing
450
+ - **`@jaypie/express`** - Express route input validation
451
+ - **CLI packages** - Commander.js integration via the commander adapter
package/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Finlayson Studio, LLC
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.