@convilyn/sdk-author 0.7.0 → 0.8.0

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.d.cts CHANGED
@@ -2,7 +2,7 @@ import { ZodTypeAny, TypeOf } from 'zod';
2
2
  import { Server } from 'node:http';
3
3
 
4
4
  /** The SDK release version (independent of the manifest schema version). */
5
- declare const VERSION = "0.7.0";
5
+ declare const VERSION = "0.8.0";
6
6
  /**
7
7
  * The schema version stamped into a compiled manifest's `sdk_version` field —
8
8
  * kept in lockstep with the Python / Go author SDKs' manifest format.
@@ -18,10 +18,29 @@ declare const MANIFEST_SDK_VERSION = "1.0.0";
18
18
  * ├── ConvilynStartupError server cannot safely start (fail-closed gate)
19
19
  * └── ConfirmationInvalidError confirmation-handshake token rejected
20
20
  */
21
+ /**
22
+ * Well-known brand for {@link ConvilynAuthorError}. `Symbol.for` resolves to the
23
+ * *same* symbol from the global registry regardless of which module instance
24
+ * (ESM vs. CJS) created it, so {@link isConvilynAuthorError} stays reliable even
25
+ * when a process ends up loading both entry points of this package (a classic
26
+ * Node.js dual-package hazard where `instanceof` across the two module graphs
27
+ * can false-negative). Prefer the guard function over `instanceof` unless you
28
+ * can guarantee a single module graph.
29
+ */
30
+ declare const CONVILYN_AUTHOR_ERROR_BRAND: unique symbol;
21
31
  /** Base class for every error the Author SDK throws. */
22
32
  declare class ConvilynAuthorError extends Error {
33
+ /** @internal brand marker — see {@link isConvilynAuthorError} */
34
+ readonly [CONVILYN_AUTHOR_ERROR_BRAND] = true;
23
35
  constructor(message: string);
24
36
  }
37
+ /**
38
+ * Reliable `err instanceof ConvilynAuthorError` replacement across module
39
+ * graphs. Use this (not `instanceof`) when the error may have crossed an
40
+ * ESM/CJS boundary — e.g. a dependency `require()`s this package while your
41
+ * own code `import`s it.
42
+ */
43
+ declare function isConvilynAuthorError(err: unknown): err is ConvilynAuthorError;
25
44
  /** Stable machine-readable reason for an {@link InvalidSignatureError}. */
26
45
  type InvalidSignatureReason = 'missing_secret' | 'missing_header' | 'invalid_timestamp' | 'timestamp_out_of_range' | 'signature_mismatch';
27
46
  /**
@@ -1155,4 +1174,4 @@ interface InvokeToolOptions {
1155
1174
  */
1156
1175
  declare function invokeTool(server: ToolServer, toolName: string, args?: Record<string, unknown>, options?: InvokeToolOptions): Promise<ToolResultWire>;
1157
1176
 
1158
- export { type BlueprintAgentConfig, type BlueprintMcpConfig, CONFIRMATION_TTL_SECONDS, type CanvasLayout, type CompiledWorkflowSpec, type ComplianceReport, type ComplianceResult, ConfirmationInvalidError, type ConfirmationInvalidReason, type ConfirmationTokenInput, ConsoleProgressBackend, ConvilynApiError, ConvilynAuthorError, ConvilynClient, type ConvilynClientOptions, ConvilynManifest, type ConvilynManifestOptions, ConvilynStartupError, DEFAULT_HMAC_TOLERANCE_SECONDS, type DataStore, type DeployHostedRequest, type DeployHostedResponse, type DeveloperRegisterRequest, type DeveloperRegisterResponse, type DeveloperServer, ENV_DEV_INSECURE, type ExportPayload, type FallbackAction, type FallbackPolicy, type FetchLike, GET_TOOL_DATA, type HumanReviewPolicy, InMemoryDataStore, InvalidSignatureError, type InvalidSignatureReason, type InvokeToolOptions, type JSONRPCErrorObject, type JSONRPCRequest, type JSONRPCResponse, JSONRPC_VERSION, MANIFEST_SDK_VERSION, OUTPUT_INLINE_THRESHOLD_BYTES, type OutputValidationPolicy, PUBLIC_SCHEMA_VERSION, type PauseTrigger, type Position, type ProgressBackend, type RequestBody, type RetryCategory, type RetryPolicy, type RollbackResponse, type RuntimeLogEntry, type RuntimeStatus, SDKConfig, type SDKConfigOptions, SERVER_ID_HEADER, SIGNATURE_HEADER, type ServeOptions, type ServerSpec, type ServerStatusResponse, type ServerSubmitRequest, type ServerSubmitResponse, type ServerVerificationStatus, type SourceType, TIMESTAMP_HEADER, TOOLS_CALL, type TestRunResponse, type TimeoutPolicy, ToolContext, type ToolDataRef, type ToolDefinition, type ToolDefinitionInput, type ToolError, type ToolHandlerResult, type ToolPaletteItem, ToolResult, type ToolResultWire, ToolServer, type ToolServerOptions, type ToolSpec, type ToolStatus, VERSION, type ValidationIssueWire, type VerifyConfirmationInput, type VerifyOptions, type Visibility, type WorkflowBlueprint, type WorkflowListItem, type WorkflowPolicies, type WorkflowServerCheck, WorkflowSpec, type WorkflowStatusResponse, type WorkflowSubmitRequest, type WorkflowSubmitResponse, type WorkflowTestResponse, type WorkflowVerificationStatus, allChecksPassed, buildWorkflowPolicies, createDataStore, createToolContext, defineTool, devInsecureRequested, failedChecks, generateRefId, invokeTool, mintConfirmationToken, normalizeForDigest, runComplianceChecks, serve, signRequest, verifyConfirmationToken, verifySignature };
1177
+ export { type BlueprintAgentConfig, type BlueprintMcpConfig, CONFIRMATION_TTL_SECONDS, type CanvasLayout, type CompiledWorkflowSpec, type ComplianceReport, type ComplianceResult, ConfirmationInvalidError, type ConfirmationInvalidReason, type ConfirmationTokenInput, ConsoleProgressBackend, ConvilynApiError, ConvilynAuthorError, ConvilynClient, type ConvilynClientOptions, ConvilynManifest, type ConvilynManifestOptions, ConvilynStartupError, DEFAULT_HMAC_TOLERANCE_SECONDS, type DataStore, type DeployHostedRequest, type DeployHostedResponse, type DeveloperRegisterRequest, type DeveloperRegisterResponse, type DeveloperServer, ENV_DEV_INSECURE, type ExportPayload, type FallbackAction, type FallbackPolicy, type FetchLike, GET_TOOL_DATA, type HumanReviewPolicy, InMemoryDataStore, InvalidSignatureError, type InvalidSignatureReason, type InvokeToolOptions, type JSONRPCErrorObject, type JSONRPCRequest, type JSONRPCResponse, JSONRPC_VERSION, MANIFEST_SDK_VERSION, OUTPUT_INLINE_THRESHOLD_BYTES, type OutputValidationPolicy, PUBLIC_SCHEMA_VERSION, type PauseTrigger, type Position, type ProgressBackend, type RequestBody, type RetryCategory, type RetryPolicy, type RollbackResponse, type RuntimeLogEntry, type RuntimeStatus, SDKConfig, type SDKConfigOptions, SERVER_ID_HEADER, SIGNATURE_HEADER, type ServeOptions, type ServerSpec, type ServerStatusResponse, type ServerSubmitRequest, type ServerSubmitResponse, type ServerVerificationStatus, type SourceType, TIMESTAMP_HEADER, TOOLS_CALL, type TestRunResponse, type TimeoutPolicy, ToolContext, type ToolDataRef, type ToolDefinition, type ToolDefinitionInput, type ToolError, type ToolHandlerResult, type ToolPaletteItem, ToolResult, type ToolResultWire, ToolServer, type ToolServerOptions, type ToolSpec, type ToolStatus, VERSION, type ValidationIssueWire, type VerifyConfirmationInput, type VerifyOptions, type Visibility, type WorkflowBlueprint, type WorkflowListItem, type WorkflowPolicies, type WorkflowServerCheck, WorkflowSpec, type WorkflowStatusResponse, type WorkflowSubmitRequest, type WorkflowSubmitResponse, type WorkflowTestResponse, type WorkflowVerificationStatus, allChecksPassed, buildWorkflowPolicies, createDataStore, createToolContext, defineTool, devInsecureRequested, failedChecks, generateRefId, invokeTool, isConvilynAuthorError, mintConfirmationToken, normalizeForDigest, runComplianceChecks, serve, signRequest, verifyConfirmationToken, verifySignature };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { ZodTypeAny, TypeOf } from 'zod';
2
2
  import { Server } from 'node:http';
3
3
 
4
4
  /** The SDK release version (independent of the manifest schema version). */
5
- declare const VERSION = "0.7.0";
5
+ declare const VERSION = "0.8.0";
6
6
  /**
7
7
  * The schema version stamped into a compiled manifest's `sdk_version` field —
8
8
  * kept in lockstep with the Python / Go author SDKs' manifest format.
@@ -18,10 +18,29 @@ declare const MANIFEST_SDK_VERSION = "1.0.0";
18
18
  * ├── ConvilynStartupError server cannot safely start (fail-closed gate)
19
19
  * └── ConfirmationInvalidError confirmation-handshake token rejected
20
20
  */
21
+ /**
22
+ * Well-known brand for {@link ConvilynAuthorError}. `Symbol.for` resolves to the
23
+ * *same* symbol from the global registry regardless of which module instance
24
+ * (ESM vs. CJS) created it, so {@link isConvilynAuthorError} stays reliable even
25
+ * when a process ends up loading both entry points of this package (a classic
26
+ * Node.js dual-package hazard where `instanceof` across the two module graphs
27
+ * can false-negative). Prefer the guard function over `instanceof` unless you
28
+ * can guarantee a single module graph.
29
+ */
30
+ declare const CONVILYN_AUTHOR_ERROR_BRAND: unique symbol;
21
31
  /** Base class for every error the Author SDK throws. */
22
32
  declare class ConvilynAuthorError extends Error {
33
+ /** @internal brand marker — see {@link isConvilynAuthorError} */
34
+ readonly [CONVILYN_AUTHOR_ERROR_BRAND] = true;
23
35
  constructor(message: string);
24
36
  }
37
+ /**
38
+ * Reliable `err instanceof ConvilynAuthorError` replacement across module
39
+ * graphs. Use this (not `instanceof`) when the error may have crossed an
40
+ * ESM/CJS boundary — e.g. a dependency `require()`s this package while your
41
+ * own code `import`s it.
42
+ */
43
+ declare function isConvilynAuthorError(err: unknown): err is ConvilynAuthorError;
25
44
  /** Stable machine-readable reason for an {@link InvalidSignatureError}. */
26
45
  type InvalidSignatureReason = 'missing_secret' | 'missing_header' | 'invalid_timestamp' | 'timestamp_out_of_range' | 'signature_mismatch';
27
46
  /**
@@ -1155,4 +1174,4 @@ interface InvokeToolOptions {
1155
1174
  */
1156
1175
  declare function invokeTool(server: ToolServer, toolName: string, args?: Record<string, unknown>, options?: InvokeToolOptions): Promise<ToolResultWire>;
1157
1176
 
1158
- export { type BlueprintAgentConfig, type BlueprintMcpConfig, CONFIRMATION_TTL_SECONDS, type CanvasLayout, type CompiledWorkflowSpec, type ComplianceReport, type ComplianceResult, ConfirmationInvalidError, type ConfirmationInvalidReason, type ConfirmationTokenInput, ConsoleProgressBackend, ConvilynApiError, ConvilynAuthorError, ConvilynClient, type ConvilynClientOptions, ConvilynManifest, type ConvilynManifestOptions, ConvilynStartupError, DEFAULT_HMAC_TOLERANCE_SECONDS, type DataStore, type DeployHostedRequest, type DeployHostedResponse, type DeveloperRegisterRequest, type DeveloperRegisterResponse, type DeveloperServer, ENV_DEV_INSECURE, type ExportPayload, type FallbackAction, type FallbackPolicy, type FetchLike, GET_TOOL_DATA, type HumanReviewPolicy, InMemoryDataStore, InvalidSignatureError, type InvalidSignatureReason, type InvokeToolOptions, type JSONRPCErrorObject, type JSONRPCRequest, type JSONRPCResponse, JSONRPC_VERSION, MANIFEST_SDK_VERSION, OUTPUT_INLINE_THRESHOLD_BYTES, type OutputValidationPolicy, PUBLIC_SCHEMA_VERSION, type PauseTrigger, type Position, type ProgressBackend, type RequestBody, type RetryCategory, type RetryPolicy, type RollbackResponse, type RuntimeLogEntry, type RuntimeStatus, SDKConfig, type SDKConfigOptions, SERVER_ID_HEADER, SIGNATURE_HEADER, type ServeOptions, type ServerSpec, type ServerStatusResponse, type ServerSubmitRequest, type ServerSubmitResponse, type ServerVerificationStatus, type SourceType, TIMESTAMP_HEADER, TOOLS_CALL, type TestRunResponse, type TimeoutPolicy, ToolContext, type ToolDataRef, type ToolDefinition, type ToolDefinitionInput, type ToolError, type ToolHandlerResult, type ToolPaletteItem, ToolResult, type ToolResultWire, ToolServer, type ToolServerOptions, type ToolSpec, type ToolStatus, VERSION, type ValidationIssueWire, type VerifyConfirmationInput, type VerifyOptions, type Visibility, type WorkflowBlueprint, type WorkflowListItem, type WorkflowPolicies, type WorkflowServerCheck, WorkflowSpec, type WorkflowStatusResponse, type WorkflowSubmitRequest, type WorkflowSubmitResponse, type WorkflowTestResponse, type WorkflowVerificationStatus, allChecksPassed, buildWorkflowPolicies, createDataStore, createToolContext, defineTool, devInsecureRequested, failedChecks, generateRefId, invokeTool, mintConfirmationToken, normalizeForDigest, runComplianceChecks, serve, signRequest, verifyConfirmationToken, verifySignature };
1177
+ export { type BlueprintAgentConfig, type BlueprintMcpConfig, CONFIRMATION_TTL_SECONDS, type CanvasLayout, type CompiledWorkflowSpec, type ComplianceReport, type ComplianceResult, ConfirmationInvalidError, type ConfirmationInvalidReason, type ConfirmationTokenInput, ConsoleProgressBackend, ConvilynApiError, ConvilynAuthorError, ConvilynClient, type ConvilynClientOptions, ConvilynManifest, type ConvilynManifestOptions, ConvilynStartupError, DEFAULT_HMAC_TOLERANCE_SECONDS, type DataStore, type DeployHostedRequest, type DeployHostedResponse, type DeveloperRegisterRequest, type DeveloperRegisterResponse, type DeveloperServer, ENV_DEV_INSECURE, type ExportPayload, type FallbackAction, type FallbackPolicy, type FetchLike, GET_TOOL_DATA, type HumanReviewPolicy, InMemoryDataStore, InvalidSignatureError, type InvalidSignatureReason, type InvokeToolOptions, type JSONRPCErrorObject, type JSONRPCRequest, type JSONRPCResponse, JSONRPC_VERSION, MANIFEST_SDK_VERSION, OUTPUT_INLINE_THRESHOLD_BYTES, type OutputValidationPolicy, PUBLIC_SCHEMA_VERSION, type PauseTrigger, type Position, type ProgressBackend, type RequestBody, type RetryCategory, type RetryPolicy, type RollbackResponse, type RuntimeLogEntry, type RuntimeStatus, SDKConfig, type SDKConfigOptions, SERVER_ID_HEADER, SIGNATURE_HEADER, type ServeOptions, type ServerSpec, type ServerStatusResponse, type ServerSubmitRequest, type ServerSubmitResponse, type ServerVerificationStatus, type SourceType, TIMESTAMP_HEADER, TOOLS_CALL, type TestRunResponse, type TimeoutPolicy, ToolContext, type ToolDataRef, type ToolDefinition, type ToolDefinitionInput, type ToolError, type ToolHandlerResult, type ToolPaletteItem, ToolResult, type ToolResultWire, ToolServer, type ToolServerOptions, type ToolSpec, type ToolStatus, VERSION, type ValidationIssueWire, type VerifyConfirmationInput, type VerifyOptions, type Visibility, type WorkflowBlueprint, type WorkflowListItem, type WorkflowPolicies, type WorkflowServerCheck, WorkflowSpec, type WorkflowStatusResponse, type WorkflowSubmitRequest, type WorkflowSubmitResponse, type WorkflowTestResponse, type WorkflowVerificationStatus, allChecksPassed, buildWorkflowPolicies, createDataStore, createToolContext, defineTool, devInsecureRequested, failedChecks, generateRefId, invokeTool, isConvilynAuthorError, mintConfirmationToken, normalizeForDigest, runComplianceChecks, serve, signRequest, verifyConfirmationToken, verifySignature };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { ConfirmationInvalidError, TOOLS_CALL, ConvilynAuthorError } from './chunk-ZNZXT5ZP.js';
2
- export { ConfirmationInvalidError, ConsoleProgressBackend, ConvilynApiError, ConvilynAuthorError, ConvilynClient, ConvilynManifest, ConvilynStartupError, DEFAULT_HMAC_TOLERANCE_SECONDS, ENV_DEV_INSECURE, GET_TOOL_DATA, InMemoryDataStore, InvalidSignatureError, JSONRPC_VERSION, MANIFEST_SDK_VERSION, OUTPUT_INLINE_THRESHOLD_BYTES, PUBLIC_SCHEMA_VERSION, SDKConfig, SERVER_ID_HEADER, SIGNATURE_HEADER, TIMESTAMP_HEADER, TOOLS_CALL, ToolContext, ToolResult, ToolServer, VERSION, WorkflowSpec, allChecksPassed, createDataStore, createToolContext, devInsecureRequested, failedChecks, generateRefId, runComplianceChecks, serve, signRequest, verifySignature } from './chunk-ZNZXT5ZP.js';
1
+ import { ConfirmationInvalidError, TOOLS_CALL, ConvilynAuthorError } from './chunk-RUBSAKX7.js';
2
+ export { ConfirmationInvalidError, ConsoleProgressBackend, ConvilynApiError, ConvilynAuthorError, ConvilynClient, ConvilynManifest, ConvilynStartupError, DEFAULT_HMAC_TOLERANCE_SECONDS, ENV_DEV_INSECURE, GET_TOOL_DATA, InMemoryDataStore, InvalidSignatureError, JSONRPC_VERSION, MANIFEST_SDK_VERSION, OUTPUT_INLINE_THRESHOLD_BYTES, PUBLIC_SCHEMA_VERSION, SDKConfig, SERVER_ID_HEADER, SIGNATURE_HEADER, TIMESTAMP_HEADER, TOOLS_CALL, ToolContext, ToolResult, ToolServer, VERSION, WorkflowSpec, allChecksPassed, createDataStore, createToolContext, devInsecureRequested, failedChecks, generateRefId, isConvilynAuthorError, runComplianceChecks, serve, signRequest, verifySignature } from './chunk-RUBSAKX7.js';
3
3
  import { zodToJsonSchema } from 'zod-to-json-schema';
4
4
  import { createHash, createHmac, timingSafeEqual } from 'crypto';
5
5
 
@@ -48,8 +48,22 @@ function compileInputSchema(schema) {
48
48
  if (json.type === "object") {
49
49
  json.additionalProperties = false;
50
50
  }
51
+ assertSchemaNotSilentlyEmpty(schema, json);
51
52
  return json;
52
53
  }
54
+ function assertSchemaNotSilentlyEmpty(schema, json) {
55
+ const shape = schema.shape;
56
+ const declaredFieldCount = isRecord(shape) ? Object.keys(shape).length : 0;
57
+ if (declaredFieldCount === 0) {
58
+ return;
59
+ }
60
+ const compiledFieldCount = isRecord(json.properties) ? Object.keys(json.properties).length : 0;
61
+ if (compiledFieldCount === 0) {
62
+ throw new Error(
63
+ `defineTool: the input schema declares ${declaredFieldCount} field(s) but zod-to-json-schema produced an empty input_schema. This usually means two separate 'zod' module instances are loaded (zod is a peerDependency \u2014 check for a nested/duplicate zod install), or the server was built with a raw 'tsc' compile instead of the documented 'tsup' build.`
64
+ );
65
+ }
66
+ }
53
67
  function defineTool(def) {
54
68
  if (!def.name) {
55
69
  throw new Error("defineTool: name is required");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/policies.ts","../src/tool.ts","../src/confirmation.ts","../src/harness.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The five high-level workflow policies an author may attach to a published\n * workflow. Grounded in `docs/contracts/sdk_public_openapi.yaml`\n * (§WorkflowPolicies) — camelCase wire, every field optional. These attach to a\n * community-workflow patch (the platform client, a later increment), so they are\n * standalone here and are NOT folded into {@link WorkflowSpec.compile}.\n */\n\nimport { ConvilynAuthorError } from './errors'\n\n/** Failure categories that trigger a retry. */\nexport type RetryCategory = 'transient' | 'rate_limited' | 'tool_error'\n\n/** When and how a failed step is retried. */\nexport interface RetryPolicy {\n /** 1–10. */\n maxAttempts?: number\n /** ≥ 0. */\n backoffMs?: number\n retryOn?: RetryCategory[]\n}\n\n/** Per-workflow wall-clock + step-count bound. */\nexport interface TimeoutPolicy {\n /** ≥ 1. */\n maxStepCount?: number\n /** ≥ 1. */\n maxWallClockSeconds?: number\n}\n\n/** Structural + quality checks the final artefact must pass. */\nexport interface OutputValidationPolicy {\n requiredSections?: string[]\n /** ≥ 0. */\n minLengthChars?: number\n qualityRubric?: string\n}\n\n/** Situations in which the workflow must pause for a human answer. */\nexport type PauseTrigger = 'ambiguity' | 'high_cost' | 'low_confidence'\n\n/** When the workflow must pause for a human. */\nexport interface HumanReviewPolicy {\n pauseFor?: PauseTrigger[]\n slotPromptStyle?: 'terse' | 'verbose'\n}\n\n/** What to do when retries are exhausted or output validation fails. */\nexport type FallbackAction = 'abort' | 'return_partial' | 'escalate'\n\n/** Behaviour after retries are exhausted / validation fails. */\nexport interface FallbackPolicy {\n action?: FallbackAction\n escalationContact?: string\n}\n\n/** The five policies; declare only those you want to constrain. */\nexport interface WorkflowPolicies {\n retry?: RetryPolicy\n timeout?: TimeoutPolicy\n outputValidation?: OutputValidationPolicy\n humanReview?: HumanReviewPolicy\n fallback?: FallbackPolicy\n}\n\nfunction requireRange(\n value: number | undefined,\n min: number,\n max: number | null,\n field: string\n): void {\n if (value === undefined) {\n return\n }\n if (!Number.isFinite(value) || value < min || (max !== null && value > max)) {\n const bound = max !== null ? `${min}–${max}` : `≥ ${min}`\n throw new ConvilynAuthorError(`${field} must be ${bound} (got ${value})`)\n }\n}\n\n/**\n * Validate + normalise a {@link WorkflowPolicies} object: range-checks the\n * numeric bounds from the contract and returns a fresh object containing only\n * the sub-policies that were supplied. Throws {@link ConvilynAuthorError} on an\n * out-of-range value.\n */\nexport function buildWorkflowPolicies(input: WorkflowPolicies): WorkflowPolicies {\n const out: WorkflowPolicies = {}\n if (input.retry) {\n requireRange(input.retry.maxAttempts, 1, 10, 'retry.maxAttempts')\n requireRange(input.retry.backoffMs, 0, null, 'retry.backoffMs')\n out.retry = { ...input.retry }\n }\n if (input.timeout) {\n requireRange(input.timeout.maxStepCount, 1, null, 'timeout.maxStepCount')\n requireRange(input.timeout.maxWallClockSeconds, 1, null, 'timeout.maxWallClockSeconds')\n out.timeout = { ...input.timeout }\n }\n if (input.outputValidation) {\n requireRange(input.outputValidation.minLengthChars, 0, null, 'outputValidation.minLengthChars')\n out.outputValidation = { ...input.outputValidation }\n }\n if (input.humanReview) {\n out.humanReview = { ...input.humanReview }\n }\n if (input.fallback) {\n out.fallback = { ...input.fallback }\n }\n return out\n}\n","/**\n * `defineTool` — declare a tool for a {@link ToolServer}. The author supplies a\n * Zod schema for the input; the SDK derives the manifest `input_schema`\n * (JSON Schema) from it via `zod-to-json-schema`, statically types the handler\n * args via `z.infer`, and validates inbound `/mcp` arguments against it at\n * runtime. (Design decision: TS has no type-hint reflection, so the\n * schema is author-supplied — Zod is the single source for schema + types +\n * validation. `zod` is a peerDependency and is **not** re-exported.)\n */\n\n// Type-only import: erased at build, so zod stays a peerDependency (the author's\n// instance is authoritative) and never enters this package's runtime bundle.\nimport type { ZodTypeAny, TypeOf } from 'zod'\nimport { zodToJsonSchema } from 'zod-to-json-schema'\nimport type { ToolContext } from './context'\nimport type { ToolResult, ToolSpec } from './types'\n\n/** A handler's return — sync or async {@link ToolResult}. */\nexport type ToolHandlerResult = ToolResult | Promise<ToolResult>\n\n/** A compiled tool: its manifest spec, its input validator, and its handler. */\nexport interface ToolDefinition {\n readonly name: string\n readonly description: string\n readonly idempotent: boolean\n /** The Zod schema; used to validate inbound `/mcp` arguments. */\n readonly inputSchema: ZodTypeAny\n /** The JSON Schema derived from `inputSchema` (manifest `input_schema`). */\n readonly jsonSchema: Record<string, unknown>\n /** Optional manifest `output_schema` (a JSON Schema object). */\n readonly outputSchema?: Record<string, unknown>\n /** Runs the tool with already-validated arguments. */\n readonly handler: (args: unknown, ctx: ToolContext) => ToolHandlerResult\n /** The manifest row for this tool. */\n toSpec(): ToolSpec\n}\n\n/** Definition object accepted by {@link defineTool}. */\nexport interface ToolDefinitionInput<S extends ZodTypeAny> {\n name: string\n description: string\n /** A Zod object schema describing the tool's arguments. */\n input: S\n idempotent: boolean\n /** Receives arguments typed by `input` (via `z.infer`) and the execution context. */\n handler: (args: TypeOf<S>, ctx: ToolContext) => ToolHandlerResult\n /** Optional JSON Schema for the tool's output (manifest only; not validated). */\n outputSchema?: Record<string, unknown>\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * Compile a Zod schema to the manifest JSON Schema shape: inline all `$ref`s,\n * drop the `$schema`/`$ref` wrapper keys, and force `additionalProperties:false`\n * on the root object so the gateway validator rejects unknown args — matching the\n * Python SDK's Pydantic output.\n */\nfunction compileInputSchema(schema: ZodTypeAny): Record<string, unknown> {\n const generated = zodToJsonSchema(schema, { $refStrategy: 'none', target: 'jsonSchema7' })\n const json: Record<string, unknown> = isRecord(generated) ? { ...generated } : {}\n delete json.$schema\n delete json.$ref\n if (json.type === 'object') {\n json.additionalProperties = false\n }\n return json\n}\n\n/**\n * Declare a tool. Returns a {@link ToolDefinition} ready to register on a\n * {@link ToolServer}. The `input` Zod schema is the single source of truth for\n * the manifest schema, the handler's argument types, and runtime validation.\n */\nexport function defineTool<S extends ZodTypeAny>(def: ToolDefinitionInput<S>): ToolDefinition {\n if (!def.name) {\n throw new Error('defineTool: name is required')\n }\n const jsonSchema = compileInputSchema(def.input)\n const handler = def.handler as (args: unknown, ctx: ToolContext) => ToolHandlerResult\n return {\n name: def.name,\n description: def.description,\n idempotent: def.idempotent,\n inputSchema: def.input,\n jsonSchema,\n outputSchema: def.outputSchema,\n handler,\n toSpec(): ToolSpec {\n const spec: ToolSpec = {\n name: def.name,\n description: def.description,\n inputSchema: jsonSchema,\n idempotent: def.idempotent,\n }\n if (def.outputSchema != null) {\n spec.outputSchema = def.outputSchema\n }\n return spec\n },\n }\n}\n","/**\n * Confirmation-handshake token signing — byte-for-byte compatible with the\n * `mcp-shared` framework and the Python / Go author SDKs, so a token minted by a\n * TS-authored server verifies against the gateway (and vice versa).\n *\n * Token wire format: `base64url(\"<expires>:<digest>:<sig>\")` (RFC 4648 url-safe,\n * **padding kept**), where\n * digest = sha256hex(canonicalJson(normalizeForDigest(arguments)))\n * sig = hmacSha256hex(secret, \"<toolName>|<expires>|<digest>\")\n *\n * This is a **distinct** scheme from the inbound request HMAC in `./auth` (which\n * signs `<timestamp>.<body>`); the two are not interchangeable.\n *\n * Byte-exactness notes:\n * - `canonicalJson` matches Python `json.dumps(sort_keys=True, separators=(\",\",\":\"))`\n * with the default `ensure_ascii=True` — every code point ≥ 0x80 is emitted as\n * `\\uXXXX` (surrogate pairs for non-BMP), keys sorted by UTF-16 code unit.\n * - `normalizeForDigest` strips volatile presigned-URL query params before hashing\n * (re-encoding kept params with Python `quote_plus` semantics) so a re-presigned\n * URL still matches the confirmed arguments.\n */\n\nimport { createHash, createHmac, timingSafeEqual } from 'node:crypto'\nimport { ConfirmationInvalidError } from './errors'\n\n/** Confirmation token lifetime (seconds); matches the framework constant. */\nexport const CONFIRMATION_TTL_SECONDS = 300\n\n/** The argument key carrying the token on the confirming re-call (stripped before digest). */\nconst CONFIRMATION_FIELD = 'confirmation_token'\n\n/** Volatile presigned-URL query params dropped before hashing (matched case-insensitively). */\nconst VOLATILE_SIGNED_URL_PARAMS = new Set([\n // S3 SigV4\n 'x-amz-algorithm',\n 'x-amz-credential',\n 'x-amz-date',\n 'x-amz-expires',\n 'x-amz-signature',\n 'x-amz-signedheaders',\n 'x-amz-security-token',\n // S3 SigV2 (legacy presign)\n 'awsaccesskeyid',\n 'signature',\n 'expires',\n // CloudFront signed URLs\n 'key-pair-id',\n 'policy',\n])\n\nconst ALWAYS_SAFE = /^[A-Za-z0-9_.~-]$/\n\n/** Python `urllib.parse.quote_plus` over UTF-8 bytes (space → '+', else %XX upper). */\nfunction quotePlus(value: string): string {\n let out = ''\n for (const byte of Buffer.from(value, 'utf8')) {\n const ch = String.fromCharCode(byte)\n if (ALWAYS_SAFE.test(ch)) {\n out += ch\n } else if (ch === ' ') {\n out += '+'\n } else {\n out += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`\n }\n }\n return out\n}\n\n/** Python `urllib.parse.unquote_plus` ('+' → space, %XX → byte) decoding to UTF-8. */\nfunction unquotePlus(value: string): string {\n const bytes: number[] = []\n for (let i = 0; i < value.length; i += 1) {\n const ch = value[i]!\n if (ch === '+') {\n bytes.push(0x20)\n } else if (ch === '%' && i + 2 < value.length) {\n bytes.push(parseInt(value.slice(i + 1, i + 3), 16))\n i += 2\n } else {\n bytes.push(ch.charCodeAt(0))\n }\n }\n return Buffer.from(bytes).toString('utf8')\n}\n\n/** Strip volatile presign params from a URL string, re-encoding kept params (quote_plus). */\nfunction stripVolatileParams(url: string): string {\n const queryStart = url.indexOf('?')\n const hashStart = url.indexOf('#', queryStart)\n const base = url.slice(0, queryStart)\n const query = url.slice(queryStart + 1, hashStart === -1 ? undefined : hashStart)\n const fragment = hashStart === -1 ? '' : url.slice(hashStart)\n\n const kept: string[] = []\n for (const pair of query.split('&')) {\n if (pair === '') {\n continue\n }\n const eq = pair.indexOf('=')\n const rawKey = eq === -1 ? pair : pair.slice(0, eq)\n const rawValue = eq === -1 ? '' : pair.slice(eq + 1)\n const key = unquotePlus(rawKey)\n if (VOLATILE_SIGNED_URL_PARAMS.has(key.toLowerCase())) {\n continue\n }\n kept.push(`${quotePlus(key)}=${quotePlus(unquotePlus(rawValue))}`)\n }\n\n const rebuiltQuery = kept.join('&')\n return rebuiltQuery === '' ? `${base}${fragment}` : `${base}?${rebuiltQuery}${fragment}`\n}\n\n/** Recursively drop volatile presign params from any URL strings within `value`. */\nexport function normalizeForDigest(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(normalizeForDigest)\n }\n if (value !== null && typeof value === 'object') {\n // Null-prototype accumulator: a plain `{}` would swallow a `__proto__` /\n // `constructor`-named key via the prototype setter, silently dropping it\n // from the digest (divergence from Python's json.dumps, which keeps it).\n const out: Record<string, unknown> = Object.create(null) as Record<string, unknown>\n for (const [k, v] of Object.entries(value)) {\n out[k] = normalizeForDigest(v)\n }\n return out\n }\n if (typeof value === 'string' && value.includes('://') && value.includes('?')) {\n return stripVolatileParams(value)\n }\n return value\n}\n\nfunction deepSortKeys(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(deepSortKeys)\n }\n if (value !== null && typeof value === 'object') {\n const source = value as Record<string, unknown>\n // Null-prototype for the same reason as normalizeForDigest: reserved key\n // names must survive as ordinary own properties.\n const out: Record<string, unknown> = Object.create(null) as Record<string, unknown>\n for (const key of Object.keys(source).sort()) {\n out[key] = deepSortKeys(source[key])\n }\n return out\n }\n return value\n}\n\n/** Match Python `json.dumps(..., sort_keys=True, separators=(\",\",\":\"))` (ensure_ascii). */\nfunction canonicalJson(value: unknown): string {\n const compact = JSON.stringify(deepSortKeys(value))\n // ensure_ascii: escape every code point >= 0x80 as \\uXXXX (surrogate pairs intact).\n return compact.replace(\n /[\\u0080-\\uffff]/g,\n (c) => `\\\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`\n )\n}\n\nfunction payloadDigest(args: Record<string, unknown>): string {\n return createHash('sha256')\n .update(canonicalJson(normalizeForDigest(args)), 'utf8')\n .digest('hex')\n}\n\nfunction sign(secret: string, toolName: string, expires: number, digest: string): string {\n return createHmac('sha256', secret)\n .update(`${toolName}|${expires}|${digest}`, 'utf8')\n .digest('hex')\n}\n\nfunction base64urlEncode(raw: string): string {\n // url-safe alphabet WITH padding kept (matches Python base64.urlsafe_b64encode).\n return Buffer.from(raw, 'utf8').toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_')\n}\n\nfunction base64urlDecode(token: string): string {\n return Buffer.from(token.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8')\n}\n\nfunction constantTimeEqual(a: string, b: string): boolean {\n const aBuf = Buffer.from(a)\n const bBuf = Buffer.from(b)\n return aBuf.length === bBuf.length && timingSafeEqual(aBuf, bBuf)\n}\n\n/** Arguments passed to {@link mintConfirmationToken} / {@link verifyConfirmationToken}. */\nexport interface ConfirmationTokenInput {\n toolName: string\n arguments: Record<string, unknown>\n /** Unix seconds at which the token expires. */\n expiresAtUnix: number\n secret: string\n}\n\n/**\n * Mint a confirmation token for a tool call, byte-for-byte compatible with the\n * gateway / Python / Go signer.\n */\nexport function mintConfirmationToken(input: ConfirmationTokenInput): string {\n if (!input.secret) {\n throw new ConfirmationInvalidError('malformed', 'confirmation secret is not configured')\n }\n const digest = payloadDigest(input.arguments)\n const sig = sign(input.secret, input.toolName, input.expiresAtUnix, digest)\n return base64urlEncode(`${input.expiresAtUnix}:${digest}:${sig}`)\n}\n\n/** Verification input (`expiresAtUnix` is ignored — it is read from the token). */\nexport interface VerifyConfirmationInput {\n toolName: string\n arguments: Record<string, unknown>\n token: string\n secret: string\n /** Override \"now\" (Unix seconds) for tests; defaults to the real clock. */\n now?: () => number\n}\n\n/**\n * Verify a confirmation token against the (re-)supplied arguments. Throws\n * {@link ConfirmationInvalidError} on a malformed / expired / mismatched token.\n * The `confirmation_token` argument (present on the confirming re-call) is\n * stripped before re-computing the digest.\n */\nexport function verifyConfirmationToken(input: VerifyConfirmationInput): void {\n if (!input.secret) {\n throw new ConfirmationInvalidError('malformed', 'confirmation secret is not configured')\n }\n const now = input.now ?? (() => Math.floor(Date.now() / 1000))\n\n let expiresStr: string | undefined\n let digest: string | undefined\n let sig: string | undefined\n try {\n ;[expiresStr, digest, sig] = base64urlDecode(input.token).split(':')\n } catch {\n throw new ConfirmationInvalidError('malformed', 'confirmation token could not be decoded')\n }\n if (expiresStr === undefined || digest === undefined || sig === undefined) {\n throw new ConfirmationInvalidError('malformed', 'confirmation token is malformed')\n }\n if (!/^\\d+$/.test(expiresStr)) {\n throw new ConfirmationInvalidError('malformed', 'confirmation token has a non-integer expiry')\n }\n const expiresAtUnix = Number(expiresStr)\n\n if (expiresAtUnix < now()) {\n throw new ConfirmationInvalidError('expired', 'confirmation token expired')\n }\n\n // Null-prototype accumulator (see normalizeForDigest): a `__proto__`-named\n // argument key must survive the strip as an ordinary own property.\n const stripped: Record<string, unknown> = Object.create(null) as Record<string, unknown>\n for (const [k, v] of Object.entries(input.arguments)) {\n if (k !== CONFIRMATION_FIELD) {\n stripped[k] = v\n }\n }\n if (!constantTimeEqual(digest, payloadDigest(stripped))) {\n throw new ConfirmationInvalidError(\n 'digest_mismatch',\n 'confirmation token does not match arguments'\n )\n }\n\n const expectedSig = sign(input.secret, input.toolName, expiresAtUnix, digest)\n if (!constantTimeEqual(sig, expectedSig)) {\n throw new ConfirmationInvalidError('signature_mismatch', 'confirmation token signature invalid')\n }\n}\n","/**\n * Local testing harness — invoke a registered tool in-process and get its wire\n * envelope back, without standing up an HTTP server. Lets authors unit-test\n * their tools (and the platform's confirmation / validation behaviour) directly\n * against a {@link ToolServer}.\n *\n * It drives the same transport-free `ToolServer.dispatch` the `/mcp` runtime\n * uses, so what you assert in a test is exactly what the gateway would receive.\n */\n\nimport { TOOLS_CALL } from './jsonrpc'\nimport { ConvilynAuthorError } from './errors'\nimport type { ToolServer } from './tool-server'\nimport type { ToolResultWire } from './tool-result-wire'\n\n/** Options for {@link invokeTool}. */\nexport interface InvokeToolOptions {\n /** `request_id` surfaced to the tool's {@link ToolContext}. */\n requestId?: string\n}\n\n/**\n * Invoke `toolName` on `server` with `args` and return the ToolResult wire\n * envelope. Throws {@link ConvilynAuthorError} if the dispatch returns a\n * JSON-RPC protocol error (unknown tool / method / bad params) — tool-level\n * outcomes (`tool_error` / `validation_error`) come back as an envelope, not a\n * throw, so they can be asserted on.\n */\nexport async function invokeTool(\n server: ToolServer,\n toolName: string,\n args: Record<string, unknown> = {},\n options: InvokeToolOptions = {}\n): Promise<ToolResultWire> {\n const response = await server.dispatch({\n jsonrpc: '2.0',\n method: TOOLS_CALL,\n params: {\n name: toolName,\n arguments: args,\n context: options.requestId !== undefined ? { request_id: options.requestId } : {},\n },\n id: 'harness',\n })\n if (response.error) {\n throw new ConvilynAuthorError(\n `invokeTool(${toolName}) failed: [${response.error.code}] ${response.error.message}`\n )\n }\n return response.result as ToolResultWire\n}\n"]}
1
+ {"version":3,"sources":["../src/policies.ts","../src/tool.ts","../src/confirmation.ts","../src/harness.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The five high-level workflow policies an author may attach to a published\n * workflow. Grounded in `docs/contracts/sdk_public_openapi.yaml`\n * (§WorkflowPolicies) — camelCase wire, every field optional. These attach to a\n * community-workflow patch (the platform client, a later increment), so they are\n * standalone here and are NOT folded into {@link WorkflowSpec.compile}.\n */\n\nimport { ConvilynAuthorError } from './errors'\n\n/** Failure categories that trigger a retry. */\nexport type RetryCategory = 'transient' | 'rate_limited' | 'tool_error'\n\n/** When and how a failed step is retried. */\nexport interface RetryPolicy {\n /** 1–10. */\n maxAttempts?: number\n /** ≥ 0. */\n backoffMs?: number\n retryOn?: RetryCategory[]\n}\n\n/** Per-workflow wall-clock + step-count bound. */\nexport interface TimeoutPolicy {\n /** ≥ 1. */\n maxStepCount?: number\n /** ≥ 1. */\n maxWallClockSeconds?: number\n}\n\n/** Structural + quality checks the final artefact must pass. */\nexport interface OutputValidationPolicy {\n requiredSections?: string[]\n /** ≥ 0. */\n minLengthChars?: number\n qualityRubric?: string\n}\n\n/** Situations in which the workflow must pause for a human answer. */\nexport type PauseTrigger = 'ambiguity' | 'high_cost' | 'low_confidence'\n\n/** When the workflow must pause for a human. */\nexport interface HumanReviewPolicy {\n pauseFor?: PauseTrigger[]\n slotPromptStyle?: 'terse' | 'verbose'\n}\n\n/** What to do when retries are exhausted or output validation fails. */\nexport type FallbackAction = 'abort' | 'return_partial' | 'escalate'\n\n/** Behaviour after retries are exhausted / validation fails. */\nexport interface FallbackPolicy {\n action?: FallbackAction\n escalationContact?: string\n}\n\n/** The five policies; declare only those you want to constrain. */\nexport interface WorkflowPolicies {\n retry?: RetryPolicy\n timeout?: TimeoutPolicy\n outputValidation?: OutputValidationPolicy\n humanReview?: HumanReviewPolicy\n fallback?: FallbackPolicy\n}\n\nfunction requireRange(\n value: number | undefined,\n min: number,\n max: number | null,\n field: string\n): void {\n if (value === undefined) {\n return\n }\n if (!Number.isFinite(value) || value < min || (max !== null && value > max)) {\n const bound = max !== null ? `${min}–${max}` : `≥ ${min}`\n throw new ConvilynAuthorError(`${field} must be ${bound} (got ${value})`)\n }\n}\n\n/**\n * Validate + normalise a {@link WorkflowPolicies} object: range-checks the\n * numeric bounds from the contract and returns a fresh object containing only\n * the sub-policies that were supplied. Throws {@link ConvilynAuthorError} on an\n * out-of-range value.\n */\nexport function buildWorkflowPolicies(input: WorkflowPolicies): WorkflowPolicies {\n const out: WorkflowPolicies = {}\n if (input.retry) {\n requireRange(input.retry.maxAttempts, 1, 10, 'retry.maxAttempts')\n requireRange(input.retry.backoffMs, 0, null, 'retry.backoffMs')\n out.retry = { ...input.retry }\n }\n if (input.timeout) {\n requireRange(input.timeout.maxStepCount, 1, null, 'timeout.maxStepCount')\n requireRange(input.timeout.maxWallClockSeconds, 1, null, 'timeout.maxWallClockSeconds')\n out.timeout = { ...input.timeout }\n }\n if (input.outputValidation) {\n requireRange(input.outputValidation.minLengthChars, 0, null, 'outputValidation.minLengthChars')\n out.outputValidation = { ...input.outputValidation }\n }\n if (input.humanReview) {\n out.humanReview = { ...input.humanReview }\n }\n if (input.fallback) {\n out.fallback = { ...input.fallback }\n }\n return out\n}\n","/**\n * `defineTool` — declare a tool for a {@link ToolServer}. The author supplies a\n * Zod schema for the input; the SDK derives the manifest `input_schema`\n * (JSON Schema) from it via `zod-to-json-schema`, statically types the handler\n * args via `z.infer`, and validates inbound `/mcp` arguments against it at\n * runtime. (Design decision: TS has no type-hint reflection, so the\n * schema is author-supplied — Zod is the single source for schema + types +\n * validation. `zod` is a peerDependency and is **not** re-exported.)\n */\n\n// Type-only import: erased at build, so zod stays a peerDependency (the author's\n// instance is authoritative) and never enters this package's runtime bundle.\nimport type { ZodTypeAny, TypeOf } from 'zod'\nimport { zodToJsonSchema } from 'zod-to-json-schema'\nimport type { ToolContext } from './context'\nimport type { ToolResult, ToolSpec } from './types'\n\n/** A handler's return — sync or async {@link ToolResult}. */\nexport type ToolHandlerResult = ToolResult | Promise<ToolResult>\n\n/** A compiled tool: its manifest spec, its input validator, and its handler. */\nexport interface ToolDefinition {\n readonly name: string\n readonly description: string\n readonly idempotent: boolean\n /** The Zod schema; used to validate inbound `/mcp` arguments. */\n readonly inputSchema: ZodTypeAny\n /** The JSON Schema derived from `inputSchema` (manifest `input_schema`). */\n readonly jsonSchema: Record<string, unknown>\n /** Optional manifest `output_schema` (a JSON Schema object). */\n readonly outputSchema?: Record<string, unknown>\n /** Runs the tool with already-validated arguments. */\n readonly handler: (args: unknown, ctx: ToolContext) => ToolHandlerResult\n /** The manifest row for this tool. */\n toSpec(): ToolSpec\n}\n\n/** Definition object accepted by {@link defineTool}. */\nexport interface ToolDefinitionInput<S extends ZodTypeAny> {\n name: string\n description: string\n /** A Zod object schema describing the tool's arguments. */\n input: S\n idempotent: boolean\n /** Receives arguments typed by `input` (via `z.infer`) and the execution context. */\n handler: (args: TypeOf<S>, ctx: ToolContext) => ToolHandlerResult\n /** Optional JSON Schema for the tool's output (manifest only; not validated). */\n outputSchema?: Record<string, unknown>\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * Compile a Zod schema to the manifest JSON Schema shape: inline all `$ref`s,\n * drop the `$schema`/`$ref` wrapper keys, and force `additionalProperties:false`\n * on the root object so the gateway validator rejects unknown args — matching the\n * Python SDK's Pydantic output.\n */\nfunction compileInputSchema(schema: ZodTypeAny): Record<string, unknown> {\n const generated = zodToJsonSchema(schema, { $refStrategy: 'none', target: 'jsonSchema7' })\n const json: Record<string, unknown> = isRecord(generated) ? { ...generated } : {}\n delete json.$schema\n delete json.$ref\n if (json.type === 'object') {\n json.additionalProperties = false\n }\n assertSchemaNotSilentlyEmpty(schema, json)\n return json\n}\n\n/**\n * `zod-to-json-schema` can come back empty (no `properties`) when it fails to\n * recognise the Zod schema — observed when a tool server is compiled with a\n * raw `tsc` build instead of the documented `tsup` pipeline, which can leave\n * two separate `zod` module instances in play (zod is a peerDependency; see\n * `docs/STABILITY.md`). A silently-empty `input_schema` in the published\n * manifest means the gateway validates nothing, so this fails loud at\n * `defineTool()` time instead of shipping a broken manifest that only\n * `convilyn-author test` would otherwise catch after the fact.\n */\nfunction assertSchemaNotSilentlyEmpty(schema: ZodTypeAny, json: Record<string, unknown>): void {\n const shape = (schema as unknown as { shape?: unknown }).shape\n const declaredFieldCount = isRecord(shape) ? Object.keys(shape).length : 0\n if (declaredFieldCount === 0) {\n // Genuinely schema-less tool, or not a plain ZodObject — nothing to\n // compare the compiled output against.\n return\n }\n const compiledFieldCount = isRecord(json.properties) ? Object.keys(json.properties).length : 0\n if (compiledFieldCount === 0) {\n throw new Error(\n `defineTool: the input schema declares ${declaredFieldCount} field(s) but ` +\n 'zod-to-json-schema produced an empty input_schema. This usually means two ' +\n \"separate 'zod' module instances are loaded (zod is a peerDependency — check \" +\n \"for a nested/duplicate zod install), or the server was built with a raw 'tsc' \" +\n \"compile instead of the documented 'tsup' build.\"\n )\n }\n}\n\n/**\n * Declare a tool. Returns a {@link ToolDefinition} ready to register on a\n * {@link ToolServer}. The `input` Zod schema is the single source of truth for\n * the manifest schema, the handler's argument types, and runtime validation.\n */\nexport function defineTool<S extends ZodTypeAny>(def: ToolDefinitionInput<S>): ToolDefinition {\n if (!def.name) {\n throw new Error('defineTool: name is required')\n }\n const jsonSchema = compileInputSchema(def.input)\n const handler = def.handler as (args: unknown, ctx: ToolContext) => ToolHandlerResult\n return {\n name: def.name,\n description: def.description,\n idempotent: def.idempotent,\n inputSchema: def.input,\n jsonSchema,\n outputSchema: def.outputSchema,\n handler,\n toSpec(): ToolSpec {\n const spec: ToolSpec = {\n name: def.name,\n description: def.description,\n inputSchema: jsonSchema,\n idempotent: def.idempotent,\n }\n if (def.outputSchema != null) {\n spec.outputSchema = def.outputSchema\n }\n return spec\n },\n }\n}\n","/**\n * Confirmation-handshake token signing — byte-for-byte compatible with the\n * `mcp-shared` framework and the Python / Go author SDKs, so a token minted by a\n * TS-authored server verifies against the gateway (and vice versa).\n *\n * Token wire format: `base64url(\"<expires>:<digest>:<sig>\")` (RFC 4648 url-safe,\n * **padding kept**), where\n * digest = sha256hex(canonicalJson(normalizeForDigest(arguments)))\n * sig = hmacSha256hex(secret, \"<toolName>|<expires>|<digest>\")\n *\n * This is a **distinct** scheme from the inbound request HMAC in `./auth` (which\n * signs `<timestamp>.<body>`); the two are not interchangeable.\n *\n * Byte-exactness notes:\n * - `canonicalJson` matches Python `json.dumps(sort_keys=True, separators=(\",\",\":\"))`\n * with the default `ensure_ascii=True` — every code point ≥ 0x80 is emitted as\n * `\\uXXXX` (surrogate pairs for non-BMP), keys sorted by UTF-16 code unit.\n * - `normalizeForDigest` strips volatile presigned-URL query params before hashing\n * (re-encoding kept params with Python `quote_plus` semantics) so a re-presigned\n * URL still matches the confirmed arguments.\n */\n\nimport { createHash, createHmac, timingSafeEqual } from 'node:crypto'\nimport { ConfirmationInvalidError } from './errors'\n\n/** Confirmation token lifetime (seconds); matches the framework constant. */\nexport const CONFIRMATION_TTL_SECONDS = 300\n\n/** The argument key carrying the token on the confirming re-call (stripped before digest). */\nconst CONFIRMATION_FIELD = 'confirmation_token'\n\n/** Volatile presigned-URL query params dropped before hashing (matched case-insensitively). */\nconst VOLATILE_SIGNED_URL_PARAMS = new Set([\n // S3 SigV4\n 'x-amz-algorithm',\n 'x-amz-credential',\n 'x-amz-date',\n 'x-amz-expires',\n 'x-amz-signature',\n 'x-amz-signedheaders',\n 'x-amz-security-token',\n // S3 SigV2 (legacy presign)\n 'awsaccesskeyid',\n 'signature',\n 'expires',\n // CloudFront signed URLs\n 'key-pair-id',\n 'policy',\n])\n\nconst ALWAYS_SAFE = /^[A-Za-z0-9_.~-]$/\n\n/** Python `urllib.parse.quote_plus` over UTF-8 bytes (space → '+', else %XX upper). */\nfunction quotePlus(value: string): string {\n let out = ''\n for (const byte of Buffer.from(value, 'utf8')) {\n const ch = String.fromCharCode(byte)\n if (ALWAYS_SAFE.test(ch)) {\n out += ch\n } else if (ch === ' ') {\n out += '+'\n } else {\n out += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`\n }\n }\n return out\n}\n\n/** Python `urllib.parse.unquote_plus` ('+' → space, %XX → byte) decoding to UTF-8. */\nfunction unquotePlus(value: string): string {\n const bytes: number[] = []\n for (let i = 0; i < value.length; i += 1) {\n const ch = value[i]!\n if (ch === '+') {\n bytes.push(0x20)\n } else if (ch === '%' && i + 2 < value.length) {\n bytes.push(parseInt(value.slice(i + 1, i + 3), 16))\n i += 2\n } else {\n bytes.push(ch.charCodeAt(0))\n }\n }\n return Buffer.from(bytes).toString('utf8')\n}\n\n/** Strip volatile presign params from a URL string, re-encoding kept params (quote_plus). */\nfunction stripVolatileParams(url: string): string {\n const queryStart = url.indexOf('?')\n const hashStart = url.indexOf('#', queryStart)\n const base = url.slice(0, queryStart)\n const query = url.slice(queryStart + 1, hashStart === -1 ? undefined : hashStart)\n const fragment = hashStart === -1 ? '' : url.slice(hashStart)\n\n const kept: string[] = []\n for (const pair of query.split('&')) {\n if (pair === '') {\n continue\n }\n const eq = pair.indexOf('=')\n const rawKey = eq === -1 ? pair : pair.slice(0, eq)\n const rawValue = eq === -1 ? '' : pair.slice(eq + 1)\n const key = unquotePlus(rawKey)\n if (VOLATILE_SIGNED_URL_PARAMS.has(key.toLowerCase())) {\n continue\n }\n kept.push(`${quotePlus(key)}=${quotePlus(unquotePlus(rawValue))}`)\n }\n\n const rebuiltQuery = kept.join('&')\n return rebuiltQuery === '' ? `${base}${fragment}` : `${base}?${rebuiltQuery}${fragment}`\n}\n\n/** Recursively drop volatile presign params from any URL strings within `value`. */\nexport function normalizeForDigest(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(normalizeForDigest)\n }\n if (value !== null && typeof value === 'object') {\n // Null-prototype accumulator: a plain `{}` would swallow a `__proto__` /\n // `constructor`-named key via the prototype setter, silently dropping it\n // from the digest (divergence from Python's json.dumps, which keeps it).\n const out: Record<string, unknown> = Object.create(null) as Record<string, unknown>\n for (const [k, v] of Object.entries(value)) {\n out[k] = normalizeForDigest(v)\n }\n return out\n }\n if (typeof value === 'string' && value.includes('://') && value.includes('?')) {\n return stripVolatileParams(value)\n }\n return value\n}\n\nfunction deepSortKeys(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(deepSortKeys)\n }\n if (value !== null && typeof value === 'object') {\n const source = value as Record<string, unknown>\n // Null-prototype for the same reason as normalizeForDigest: reserved key\n // names must survive as ordinary own properties.\n const out: Record<string, unknown> = Object.create(null) as Record<string, unknown>\n for (const key of Object.keys(source).sort()) {\n out[key] = deepSortKeys(source[key])\n }\n return out\n }\n return value\n}\n\n/** Match Python `json.dumps(..., sort_keys=True, separators=(\",\",\":\"))` (ensure_ascii). */\nfunction canonicalJson(value: unknown): string {\n const compact = JSON.stringify(deepSortKeys(value))\n // ensure_ascii: escape every code point >= 0x80 as \\uXXXX (surrogate pairs intact).\n return compact.replace(\n /[\\u0080-\\uffff]/g,\n (c) => `\\\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`\n )\n}\n\nfunction payloadDigest(args: Record<string, unknown>): string {\n return createHash('sha256')\n .update(canonicalJson(normalizeForDigest(args)), 'utf8')\n .digest('hex')\n}\n\nfunction sign(secret: string, toolName: string, expires: number, digest: string): string {\n return createHmac('sha256', secret)\n .update(`${toolName}|${expires}|${digest}`, 'utf8')\n .digest('hex')\n}\n\nfunction base64urlEncode(raw: string): string {\n // url-safe alphabet WITH padding kept (matches Python base64.urlsafe_b64encode).\n return Buffer.from(raw, 'utf8').toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_')\n}\n\nfunction base64urlDecode(token: string): string {\n return Buffer.from(token.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8')\n}\n\nfunction constantTimeEqual(a: string, b: string): boolean {\n const aBuf = Buffer.from(a)\n const bBuf = Buffer.from(b)\n return aBuf.length === bBuf.length && timingSafeEqual(aBuf, bBuf)\n}\n\n/** Arguments passed to {@link mintConfirmationToken} / {@link verifyConfirmationToken}. */\nexport interface ConfirmationTokenInput {\n toolName: string\n arguments: Record<string, unknown>\n /** Unix seconds at which the token expires. */\n expiresAtUnix: number\n secret: string\n}\n\n/**\n * Mint a confirmation token for a tool call, byte-for-byte compatible with the\n * gateway / Python / Go signer.\n */\nexport function mintConfirmationToken(input: ConfirmationTokenInput): string {\n if (!input.secret) {\n throw new ConfirmationInvalidError('malformed', 'confirmation secret is not configured')\n }\n const digest = payloadDigest(input.arguments)\n const sig = sign(input.secret, input.toolName, input.expiresAtUnix, digest)\n return base64urlEncode(`${input.expiresAtUnix}:${digest}:${sig}`)\n}\n\n/** Verification input (`expiresAtUnix` is ignored — it is read from the token). */\nexport interface VerifyConfirmationInput {\n toolName: string\n arguments: Record<string, unknown>\n token: string\n secret: string\n /** Override \"now\" (Unix seconds) for tests; defaults to the real clock. */\n now?: () => number\n}\n\n/**\n * Verify a confirmation token against the (re-)supplied arguments. Throws\n * {@link ConfirmationInvalidError} on a malformed / expired / mismatched token.\n * The `confirmation_token` argument (present on the confirming re-call) is\n * stripped before re-computing the digest.\n */\nexport function verifyConfirmationToken(input: VerifyConfirmationInput): void {\n if (!input.secret) {\n throw new ConfirmationInvalidError('malformed', 'confirmation secret is not configured')\n }\n const now = input.now ?? (() => Math.floor(Date.now() / 1000))\n\n let expiresStr: string | undefined\n let digest: string | undefined\n let sig: string | undefined\n try {\n ;[expiresStr, digest, sig] = base64urlDecode(input.token).split(':')\n } catch {\n throw new ConfirmationInvalidError('malformed', 'confirmation token could not be decoded')\n }\n if (expiresStr === undefined || digest === undefined || sig === undefined) {\n throw new ConfirmationInvalidError('malformed', 'confirmation token is malformed')\n }\n if (!/^\\d+$/.test(expiresStr)) {\n throw new ConfirmationInvalidError('malformed', 'confirmation token has a non-integer expiry')\n }\n const expiresAtUnix = Number(expiresStr)\n\n if (expiresAtUnix < now()) {\n throw new ConfirmationInvalidError('expired', 'confirmation token expired')\n }\n\n // Null-prototype accumulator (see normalizeForDigest): a `__proto__`-named\n // argument key must survive the strip as an ordinary own property.\n const stripped: Record<string, unknown> = Object.create(null) as Record<string, unknown>\n for (const [k, v] of Object.entries(input.arguments)) {\n if (k !== CONFIRMATION_FIELD) {\n stripped[k] = v\n }\n }\n if (!constantTimeEqual(digest, payloadDigest(stripped))) {\n throw new ConfirmationInvalidError(\n 'digest_mismatch',\n 'confirmation token does not match arguments'\n )\n }\n\n const expectedSig = sign(input.secret, input.toolName, expiresAtUnix, digest)\n if (!constantTimeEqual(sig, expectedSig)) {\n throw new ConfirmationInvalidError('signature_mismatch', 'confirmation token signature invalid')\n }\n}\n","/**\n * Local testing harness — invoke a registered tool in-process and get its wire\n * envelope back, without standing up an HTTP server. Lets authors unit-test\n * their tools (and the platform's confirmation / validation behaviour) directly\n * against a {@link ToolServer}.\n *\n * It drives the same transport-free `ToolServer.dispatch` the `/mcp` runtime\n * uses, so what you assert in a test is exactly what the gateway would receive.\n */\n\nimport { TOOLS_CALL } from './jsonrpc'\nimport { ConvilynAuthorError } from './errors'\nimport type { ToolServer } from './tool-server'\nimport type { ToolResultWire } from './tool-result-wire'\n\n/** Options for {@link invokeTool}. */\nexport interface InvokeToolOptions {\n /** `request_id` surfaced to the tool's {@link ToolContext}. */\n requestId?: string\n}\n\n/**\n * Invoke `toolName` on `server` with `args` and return the ToolResult wire\n * envelope. Throws {@link ConvilynAuthorError} if the dispatch returns a\n * JSON-RPC protocol error (unknown tool / method / bad params) — tool-level\n * outcomes (`tool_error` / `validation_error`) come back as an envelope, not a\n * throw, so they can be asserted on.\n */\nexport async function invokeTool(\n server: ToolServer,\n toolName: string,\n args: Record<string, unknown> = {},\n options: InvokeToolOptions = {}\n): Promise<ToolResultWire> {\n const response = await server.dispatch({\n jsonrpc: '2.0',\n method: TOOLS_CALL,\n params: {\n name: toolName,\n arguments: args,\n context: options.requestId !== undefined ? { request_id: options.requestId } : {},\n },\n id: 'harness',\n })\n if (response.error) {\n throw new ConvilynAuthorError(\n `invokeTool(${toolName}) failed: [${response.error.code}] ${response.error.message}`\n )\n }\n return response.result as ToolResultWire\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@convilyn/sdk-author",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Official TypeScript/JavaScript Author SDK for Convilyn — build tool servers and workflow specs for the platform.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {