toolcraft 0.0.304 → 0.0.306

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/composition.json CHANGED
@@ -98,7 +98,7 @@
98
98
  },
99
99
  {
100
100
  "name": "tiny-http-mcp-server",
101
- "version": "0.1.20",
101
+ "version": "0.1.21",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.304",
116
+ "version": "0.0.306",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.304",
126
+ "version": "0.0.306",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -98,7 +98,7 @@
98
98
  },
99
99
  {
100
100
  "name": "tiny-http-mcp-server",
101
- "version": "0.1.20",
101
+ "version": "0.1.21",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.304",
116
+ "version": "0.0.306",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.304",
126
+ "version": "0.0.306",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -18,7 +18,7 @@
18
18
  },
19
19
  {
20
20
  "name": "tiny-http-mcp-server",
21
- "version": "0.1.20",
21
+ "version": "0.1.21",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,6 +36,8 @@ Legacy SSE mode opens a GET stream and posts messages to the endpoint announced
36
36
  by the server. Announced endpoints must remain on the original origin without
37
37
  embedded credentials or fragments; endpoint changes close the connection.
38
38
  Both transports accept the same headers, OAuth provider and response limits.
39
+ HTTP failures expose `HttpTransportError.status` and `.method`, so callers can
40
+ make transport decisions without parsing error messages.
39
41
 
40
42
  ## OAuth HTTP support
41
43
 
@@ -583,6 +583,11 @@ interface StdioTransportOptions {
583
583
  spawn?: StdioSpawn;
584
584
  }
585
585
  type HttpTransportFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
586
+ declare class HttpTransportError extends Error {
587
+ readonly status: number;
588
+ readonly method: "GET" | "POST" | "DELETE";
589
+ constructor(message: string, status: number, method: "GET" | "POST" | "DELETE");
590
+ }
586
591
  interface HttpTransportOptions {
587
592
  url: string;
588
593
  /** Legacy SSE uses a GET stream that announces the RPC POST endpoint. */
@@ -743,5 +748,5 @@ declare class JsonRpcMessageLayer {
743
748
  private handleCancellationNotification;
744
749
  }
745
750
 
746
- export { ERROR_INTERNAL, ERROR_INVALID_PARAMS, ERROR_INVALID_REQUEST, ERROR_METHOD_NOT_FOUND, ERROR_PARSE, HttpTransport, JsonRpcMessageLayer, McpClient, McpError, OAuthMetadataDiscovery, StdioTransport, createInMemoryTransportPair, createSdkTestPair, createTestPair, discoverOAuthMetadata, fetchMcpResponse };
751
+ export { ERROR_INTERNAL, ERROR_INVALID_PARAMS, ERROR_INVALID_REQUEST, ERROR_METHOD_NOT_FOUND, ERROR_PARSE, HttpTransport, HttpTransportError, JsonRpcMessageLayer, McpClient, McpError, OAuthMetadataDiscovery, StdioTransport, createInMemoryTransportPair, createSdkTestPair, createTestPair, discoverOAuthMetadata, fetchMcpResponse };
747
752
  export type { AudioContent, BlobResourceContents, CacheableResultMetadata, CallToolOptions, CallToolParams, CallToolResult, ClientCapabilities, CompleteArgument, CompleteParams, CompleteResult, Completion, ConnectResult, ContentItem, CreateMessageParams, CreateMessageResult, ElicitationParams, ElicitationResult, EmbeddedResource, GetPromptParams, GetPromptResult, HttpTransportFetch, HttpTransportOptions, ImageContent, InMemoryTransportPair, IncludeContext, InitializeParams, InitializeResult, JsonRpcErrorObject, JsonRpcErrorResponse, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcRequestOptions, JsonRpcResponse, JsonRpcSuccessResponse, LogLevel, LogMessage, McpClientConnection, McpClientOptions, McpRequestContext, McpSubscription, McpTransport, McpTransportClosedEvent, ModelHint, ModelPreferences, NotificationFilter, OAuthAuthorizationServerMetadata, OAuthClientProvider, OAuthClientProviderOptions, OAuthDiscoveryCache, OAuthDiscoveryResult, OAuthMetadataFetch, OAuthProtectedResourceMetadata, OAuthSessionStore, OAuthUnauthorizedChallenge, PaginatedParams, PaginatedResult, ProgressParams, ProgressToken, PromptMessage, PromptReference, ReadResourceParams, RequestId, ResourceContents, ResourceReference, ResultMetadata, Root, SamplingContent, SamplingMessage, SdkTestPair, ServerCapabilities, StdioSpawn, StdioTransportOptions, StoredOAuthSession, SubscriptionOptions, TextContent, TextResourceContents, Tool, ToolResultContent, ToolUseContent };
@@ -6505,6 +6505,16 @@ async function createTestPair(server, createClient) {
6505
6505
  };
6506
6506
  return { client, cleanup };
6507
6507
  }
6508
+ var HttpTransportError = class extends Error {
6509
+ constructor(message, status, method) {
6510
+ super(message);
6511
+ this.status = status;
6512
+ this.method = method;
6513
+ this.name = "HttpTransportError";
6514
+ }
6515
+ status;
6516
+ method;
6517
+ };
6508
6518
  function defaultStdioSpawn(command, args, options) {
6509
6519
  return spawn2(command, args, options);
6510
6520
  }
@@ -6819,7 +6829,7 @@ var HttpTransport = class {
6819
6829
  if (hasSessionId && response.status === 404) {
6820
6830
  void response.body?.cancel().catch(() => void 0);
6821
6831
  this.sessionId = void 0;
6822
- this.dispose(new Error("HTTP transport session expired (404 response)"));
6832
+ this.dispose(new HttpTransportError("HTTP transport session expired (404 response)", 404, "POST"));
6823
6833
  return;
6824
6834
  }
6825
6835
  if (await this.throwForPostHttpError(
@@ -6958,7 +6968,7 @@ var HttpTransport = class {
6958
6968
  const responseBody = (await readBoundedResponseText(response, this.maxResponseBytes, this.openResponseReaders, signal)).trim();
6959
6969
  const statusDescriptor = `${response.status} ${response.statusText}`.trim();
6960
6970
  const message = responseBody.length === 0 ? `HTTP transport DELETE failed (${statusDescriptor})` : `HTTP transport DELETE failed (${statusDescriptor}): ${responseBody}`;
6961
- throw new Error(message);
6971
+ throw new HttpTransportError(message, response.status, "DELETE");
6962
6972
  }
6963
6973
  async consumeGetSseStream() {
6964
6974
  const response = await this.fetchWithOAuthRetry({
@@ -6971,18 +6981,19 @@ var HttpTransport = class {
6971
6981
  }
6972
6982
  if (response.status === 405) {
6973
6983
  void response.body?.cancel().catch(() => void 0);
6984
+ if (this.mode === "sse") throw new HttpTransportError("Legacy SSE GET failed (405)", 405, "GET");
6974
6985
  throw new HttpTransportGetSseNotSupportedError();
6975
6986
  }
6976
6987
  if (response.status === 404) {
6977
6988
  void response.body?.cancel().catch(() => void 0);
6978
6989
  this.sessionId = void 0;
6979
- throw new Error("HTTP transport session expired (GET 404 response)");
6990
+ throw new HttpTransportError("HTTP transport session expired (GET 404 response)", 404, "GET");
6980
6991
  }
6981
6992
  if (!response.ok) {
6982
6993
  const responseBody = (await readBoundedResponseText(response, this.maxResponseBytes, this.openResponseReaders)).trim();
6983
6994
  const statusDescriptor = `${response.status} ${response.statusText}`.trim();
6984
6995
  const message = responseBody.length === 0 ? `HTTP transport GET failed (${statusDescriptor})` : `HTTP transport GET failed (${statusDescriptor}): ${responseBody}`;
6985
- throw new Error(message);
6996
+ throw new HttpTransportError(message, response.status, "GET");
6986
6997
  }
6987
6998
  const contentType = response.headers.get("Content-Type");
6988
6999
  if (contentType === null) {
@@ -7043,7 +7054,7 @@ var HttpTransport = class {
7043
7054
  }
7044
7055
  const statusDescriptor = `${response.status} ${response.statusText}`.trim();
7045
7056
  const message = responseBody.length === 0 ? `HTTP transport POST failed (${statusDescriptor})` : `HTTP transport POST failed (${statusDescriptor}): ${responseBody}`;
7046
- throw new Error(message);
7057
+ throw new HttpTransportError(message, response.status, "POST");
7047
7058
  }
7048
7059
  async maybeHandleUnauthorizedResponse(response) {
7049
7060
  if (response.status !== 401 || this.oauthProvider === void 0) {
@@ -8123,6 +8134,7 @@ export {
8123
8134
  ERROR_METHOD_NOT_FOUND,
8124
8135
  ERROR_PARSE,
8125
8136
  HttpTransport,
8137
+ HttpTransportError,
8126
8138
  JsonRpcMessageLayer,
8127
8139
  McpClient,
8128
8140
  McpError,
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.304",
11
+ "version": "0.0.306",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -11,6 +11,7 @@ and JSON Schema generation.
11
11
  - Runtime validation with `validateValue()`
12
12
  - JSON Schema serialization via `toJsonSchema()`
13
13
  - JSON Schema document serialization via `toJsonSchemaDocument()`
14
+ - Native JSON Schema compilation and property projection with reference support
14
15
 
15
16
  ## Usage
16
17
 
@@ -83,6 +84,16 @@ const validation = validateValue(schema, {
83
84
  - Invalid input returns `{ ok: false, issues }` with path-aware diagnostics.
84
85
  - Validation applies defaults from schema descriptors.
85
86
 
87
+ `compileJsonSchema(document, options)` validates complete native JSON Schema
88
+ documents. `projectJsonSchemaProperties(document, options)` supplies stable
89
+ property names, unconditional required metadata, resolved schema annotations,
90
+ and candidate validators for CLI generation. It follows references, compositions,
91
+ embedded resource IDs and conditional declarations using the same compiler.
92
+ Property candidate validators accept values matching at least one declaration;
93
+ validate the complete object to enforce branch-dependent and combined constraints.
94
+ Both functions accept a `registry` for external schema documents without network
95
+ fetching.
96
+
86
97
  ## Environment Variables
87
98
 
88
99
  This package exposes no environment variables.
@@ -185,6 +185,8 @@ export { isJsonValue } from "./json.js";
185
185
  export { cloneDefaultValue } from "./clone-default.js";
186
186
  export { unicodeLength } from "./json-schema/utils.js";
187
187
  export { compileJsonSchema, formatIssues } from "./json-schema/index.js";
188
+ export { projectJsonSchemaProperties } from "./json-schema/properties.js";
189
+ export type { JsonSchemaProperty } from "./json-schema/properties.js";
188
190
  export { normalizeLegacyNullability } from "./json-schema/normalize-nullability.js";
189
191
  export { withJsonSchema, nativeJsonSchema } from "./native-json-schema.js";
190
192
  export type { NativeSchema } from "./native-json-schema.js";
@@ -329,5 +329,6 @@ export { isJsonValue } from "./json.js";
329
329
  export { cloneDefaultValue } from "./clone-default.js";
330
330
  export { unicodeLength } from "./json-schema/utils.js";
331
331
  export { compileJsonSchema, formatIssues } from "./json-schema/index.js";
332
+ export { projectJsonSchemaProperties } from "./json-schema/properties.js";
332
333
  export { normalizeLegacyNullability } from "./json-schema/normalize-nullability.js";
333
334
  export { withJsonSchema, nativeJsonSchema } from "./native-json-schema.js";
@@ -0,0 +1,16 @@
1
+ import type { ValidationResult } from "../validate.js";
2
+ import type { CompileJsonSchemaOptions } from "./types.js";
3
+ export interface JsonSchemaProperty {
4
+ readonly name: string;
5
+ /** Required regardless of the object's selected alternative or condition. */
6
+ readonly required: boolean;
7
+ /** Isolated annotation/schema copies, including resolved references. */
8
+ readonly schemas: readonly unknown[];
9
+ /** Candidate hint: accepts a value matching at least one advertised declaration.
10
+ * Validate the complete object to enforce compositions and conditional rules. */
11
+ validate(value: unknown): ValidationResult<unknown>;
12
+ }
13
+ /** Project names and candidate validators while retaining the native reference graph.
14
+ * Property hints cover declarations in refs, compositions and conditional branches;
15
+ * full object validation remains necessary for branch-dependent constraints. */
16
+ export declare function projectJsonSchemaProperties(schema: unknown, options?: CompileJsonSchemaOptions): readonly JsonSchemaProperty[];
@@ -0,0 +1,129 @@
1
+ import { compileGraph } from "./compiler.js";
2
+ import { evaluateSchema } from "./evaluate.js";
3
+ import { isObject } from "./utils.js";
4
+ function referenceNodes(graph, node) {
5
+ if (!isObject(node.schema))
6
+ return [];
7
+ return ["$ref", "$dynamicRef", "$recursiveRef"].flatMap(keyword => typeof node.schema === "object" && typeof node.schema[keyword] === "string"
8
+ ? [graph.resolve(node, node.schema[keyword])] : []);
9
+ }
10
+ function ignoresSiblings(node) {
11
+ return node.dialect === "draft7" && isObject(node.schema) && typeof node.schema.$ref === "string";
12
+ }
13
+ function requiredFor(graph, node, name, ancestors = new Set()) {
14
+ if (!isObject(node.schema) || ancestors.has(node))
15
+ return false;
16
+ const next = new Set(ancestors).add(node);
17
+ const referenced = referenceNodes(graph, node).some(target => requiredFor(graph, target, name, next));
18
+ if (ignoresSiblings(node))
19
+ return referenced;
20
+ if (referenced || (Array.isArray(node.schema.required) && node.schema.required.includes(name)))
21
+ return true;
22
+ for (const keyword of ["allOf", "anyOf", "oneOf"]) {
23
+ const branches = node.schema[keyword];
24
+ if (!Array.isArray(branches))
25
+ continue;
26
+ const requirements = branches.map((_branch, index) => {
27
+ const child = node.children.get(`${keyword}/${index}`);
28
+ return child !== undefined && requiredFor(graph, child, name, next);
29
+ });
30
+ if (keyword === "allOf" ? requirements.some(Boolean) : requirements.every(Boolean))
31
+ return true;
32
+ }
33
+ return false;
34
+ }
35
+ function annotationSchemas(graph, root) {
36
+ const seen = new Set();
37
+ const schemas = [];
38
+ const visit = (node) => {
39
+ if (seen.has(node))
40
+ return;
41
+ seen.add(node);
42
+ if (!ignoresSiblings(node))
43
+ schemas.push(structuredClone(node.schema));
44
+ for (const target of referenceNodes(graph, node))
45
+ visit(target);
46
+ if (ignoresSiblings(node) || !isObject(node.schema))
47
+ return;
48
+ for (const keyword of ["allOf", "anyOf", "oneOf"]) {
49
+ const branches = node.schema[keyword];
50
+ if (!Array.isArray(branches))
51
+ continue;
52
+ branches.forEach((_branch, index) => {
53
+ const child = node.children.get(`${keyword}/${index}`);
54
+ if (child)
55
+ visit(child);
56
+ });
57
+ }
58
+ };
59
+ visit(root);
60
+ return schemas;
61
+ }
62
+ /** Project names and candidate validators while retaining the native reference graph.
63
+ * Property hints cover declarations in refs, compositions and conditional branches;
64
+ * full object validation remains necessary for branch-dependent constraints. */
65
+ export function projectJsonSchemaProperties(schema, options = {}) {
66
+ const graph = compileGraph(structuredClone(schema), {
67
+ ...options, ...(options.registry === undefined ? {} : { registry: structuredClone(options.registry) })
68
+ });
69
+ const declarations = new Map();
70
+ const seen = new Set();
71
+ const visit = (node) => {
72
+ if (seen.has(node) || !isObject(node.schema))
73
+ return;
74
+ seen.add(node);
75
+ for (const target of referenceNodes(graph, node))
76
+ visit(target);
77
+ if (ignoresSiblings(node))
78
+ return;
79
+ if (isObject(node.schema.properties)) {
80
+ for (const name of Object.keys(node.schema.properties)) {
81
+ const child = node.children.get(`properties/${name}`);
82
+ if (!child)
83
+ continue;
84
+ const sources = declarations.get(name) ?? new Set();
85
+ sources.add(child);
86
+ declarations.set(name, sources);
87
+ }
88
+ }
89
+ for (const keyword of ["allOf", "anyOf", "oneOf"]) {
90
+ const branches = node.schema[keyword];
91
+ if (!Array.isArray(branches))
92
+ continue;
93
+ branches.forEach((_branch, index) => {
94
+ const child = node.children.get(`${keyword}/${index}`);
95
+ if (child)
96
+ visit(child);
97
+ });
98
+ }
99
+ for (const keyword of ["then", "else", "dependentSchemas"]) {
100
+ if (keyword === "dependentSchemas" && isObject(node.schema.dependentSchemas)) {
101
+ for (const key of Object.keys(node.schema.dependentSchemas)) {
102
+ const child = node.children.get(`dependentSchemas/${key}`);
103
+ if (child)
104
+ visit(child);
105
+ }
106
+ }
107
+ else {
108
+ const child = node.children.get(keyword);
109
+ if (child)
110
+ visit(child);
111
+ }
112
+ }
113
+ };
114
+ visit(graph.root);
115
+ return [...declarations.keys()].sort().map(name => {
116
+ const sources = [...declarations.get(name)];
117
+ return {
118
+ name,
119
+ required: requiredFor(graph, graph.root, name),
120
+ schemas: sources.flatMap(node => annotationSchemas(graph, node)),
121
+ validate(value) {
122
+ const results = sources.map(node => evaluateSchema({ ...graph, root: node }, value));
123
+ if (results.some(result => result.valid))
124
+ return { ok: true, value };
125
+ return { ok: false, issues: results.flatMap(result => result.issues) };
126
+ }
127
+ };
128
+ });
129
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.304",
3
+ "version": "0.0.306",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft",
3
- "version": "0.0.304",
3
+ "version": "0.0.306",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -158,7 +158,7 @@
158
158
  "yaml"
159
159
  ],
160
160
  "optionalDependencies": {
161
- "toolcraft-schema": "0.0.304",
161
+ "toolcraft-schema": "0.0.306",
162
162
  "toolcraft-design": "*",
163
163
  "@poe-code/frontmatter": "*",
164
164
  "@poe-code/agent-mcp-config": "*",