@zuplo/cli 7.3.2 → 7.4.3
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/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/cmds/lint.d.ts +9 -0
- package/dist/cmds/lint.d.ts.map +1 -0
- package/dist/cmds/lint.js +67 -0
- package/dist/cmds/lint.js.map +1 -0
- package/dist/lint/handler.d.ts +10 -0
- package/dist/lint/handler.d.ts.map +1 -0
- package/dist/lint/handler.js +60 -0
- package/dist/lint/handler.js.map +1 -0
- package/dist/lint/resolve-binary.d.ts +20 -0
- package/dist/lint/resolve-binary.d.ts.map +1 -0
- package/dist/lint/resolve-binary.js +71 -0
- package/dist/lint/resolve-binary.js.map +1 -0
- package/dist/lint/resolve-binary.test.d.ts +2 -0
- package/dist/lint/resolve-binary.test.d.ts.map +1 -0
- package/dist/lint/resolve-binary.test.js +155 -0
- package/dist/lint/resolve-binary.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@inquirer/checkbox/package.json +5 -4
- package/node_modules/@inquirer/confirm/dist/index.d.ts +1 -1
- package/node_modules/@inquirer/confirm/package.json +4 -3
- package/node_modules/@inquirer/core/README.md +9 -3
- package/node_modules/@inquirer/core/dist/lib/hook-engine.d.ts +2 -8
- package/node_modules/@inquirer/core/dist/lib/use-memo.js +1 -1
- package/node_modules/@inquirer/core/dist/lib/use-state.d.ts +5 -2
- package/node_modules/@inquirer/core/dist/lib/use-state.js +7 -2
- package/node_modules/@inquirer/core/package.json +5 -4
- package/node_modules/@inquirer/editor/dist/index.d.ts +1 -1
- package/node_modules/@inquirer/editor/package.json +5 -4
- package/node_modules/@inquirer/expand/README.md +1 -1
- package/node_modules/@inquirer/expand/package.json +4 -3
- package/node_modules/@inquirer/external-editor/README.md +13 -0
- package/node_modules/@inquirer/external-editor/package.json +4 -3
- package/node_modules/@inquirer/figures/package.json +4 -3
- package/node_modules/@inquirer/input/package.json +4 -3
- package/node_modules/@inquirer/number/dist/index.d.ts +1 -1
- package/node_modules/@inquirer/number/dist/index.js +1 -6
- package/node_modules/@inquirer/number/dist/is-step-of.d.ts +1 -0
- package/node_modules/@inquirer/number/dist/is-step-of.js +22 -0
- package/node_modules/@inquirer/number/package.json +4 -3
- package/node_modules/@inquirer/password/package.json +4 -3
- package/node_modules/@inquirer/rawlist/package.json +4 -3
- package/node_modules/@inquirer/search/README.md +9 -8
- package/node_modules/@inquirer/search/dist/index.d.ts +1 -0
- package/node_modules/@inquirer/search/dist/index.js +6 -1
- package/node_modules/@inquirer/search/package.json +5 -4
- package/node_modules/@inquirer/select/package.json +5 -4
- package/node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.js +4 -2
- package/node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.mjs +4 -2
- package/node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.js +5 -5
- package/node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.mjs +5 -5
- package/node_modules/@posthog/core/dist/error-tracking/parsers/base.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/error-tracking/parsers/base.js +2 -1
- package/node_modules/@posthog/core/dist/error-tracking/parsers/base.mjs +2 -1
- package/node_modules/@posthog/core/dist/posthog-core.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/posthog-core.js +1 -0
- package/node_modules/@posthog/core/dist/posthog-core.mjs +1 -0
- package/node_modules/@posthog/core/package.json +1 -1
- package/node_modules/@posthog/core/src/error-tracking/coercers/error-coercer.ts +8 -2
- package/node_modules/@posthog/core/src/error-tracking/coercers/error-event-coercer.spec.ts +33 -0
- package/node_modules/@posthog/core/src/error-tracking/coercers/error-event-coercer.ts +13 -6
- package/node_modules/@posthog/core/src/error-tracking/error-properties-builder.coerce.spec.ts +15 -0
- package/node_modules/@posthog/core/src/error-tracking/parsers/base.spec.ts +34 -0
- package/node_modules/@posthog/core/src/error-tracking/parsers/base.ts +10 -2
- package/node_modules/@posthog/core/src/posthog-core.ts +1 -0
- package/node_modules/@zuplo/core/customer.cli.minified.js +239 -239
- package/node_modules/@zuplo/core/index.minified.js +253 -253
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +1 -1
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/out/esm/chunk-NHSMO7UN.js +409 -0
- package/node_modules/@zuplo/runtime/out/esm/chunk-NHSMO7UN.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/types/index.d.ts +108 -69
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/node_modules/negotiator/lib/accept.js +54 -0
- package/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/negotiator/package.json +16 -10
- package/package.json +13 -6
- package/node_modules/@inquirer/external-editor/dist/errors/CreateFileError.d.ts +0 -10
- package/node_modules/@inquirer/external-editor/dist/errors/CreateFileError.js +0 -13
- package/node_modules/@inquirer/external-editor/dist/errors/LaunchEditorError.d.ts +0 -10
- package/node_modules/@inquirer/external-editor/dist/errors/LaunchEditorError.js +0 -13
- package/node_modules/@inquirer/external-editor/dist/errors/ReadFileError.d.ts +0 -10
- package/node_modules/@inquirer/external-editor/dist/errors/ReadFileError.js +0 -13
- package/node_modules/@inquirer/external-editor/dist/errors/RemoveFileError.d.ts +0 -10
- package/node_modules/@inquirer/external-editor/dist/errors/RemoveFileError.js +0 -13
- package/node_modules/@zuplo/runtime/out/esm/chunk-YOMMW6SX.js +0 -409
- package/node_modules/@zuplo/runtime/out/esm/chunk-YOMMW6SX.js.map +0 -1
- package/node_modules/negotiator/HISTORY.md +0 -114
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-YOMMW6SX.js.LEGAL.txt → chunk-NHSMO7UN.js.LEGAL.txt} +0 -0
|
@@ -345,8 +345,9 @@ export declare interface AIGatewayConfigurationLoaderV2InboundPolicyOptions {
|
|
|
345
345
|
* identifiers, API keys and other credentials) using the in-gateway DLP
|
|
346
346
|
* engine, and applies per-rule actions: mask, block, or log. Detection runs
|
|
347
347
|
* entirely inside the gateway; nothing is sent to a third-party scanning
|
|
348
|
-
* service. Streaming responses are scanned as they stream
|
|
349
|
-
* with a sliding boundary window
|
|
348
|
+
* service. Streaming responses are scanned as they stream by default (chunk
|
|
349
|
+
* by chunk with a sliding boundary window); `streaming.mode: "buffer"`
|
|
350
|
+
* instead collects the whole response and scans it once as one document.
|
|
350
351
|
*
|
|
351
352
|
* Options are validated at request time and invalid options fail closed with
|
|
352
353
|
* a ConfigurationError. Content that cannot be inspected is denied by
|
|
@@ -367,13 +368,13 @@ export declare function AIGatewayDlpInboundPolicy(
|
|
|
367
368
|
): Promise<ZuploRequest | Response>;
|
|
368
369
|
|
|
369
370
|
/**
|
|
370
|
-
* The options for the Data Loss Prevention (DLP) policy. Scans the content of AI requests and responses — system prompts, messages, and tool-call arguments — for sensitive data such as credit cards, national identifiers, and API keys, applying a per-rule action (mask, block, or log). Detection runs entirely inside the gateway
|
|
371
|
+
* The options for the Data Loss Prevention (DLP) policy. Scans the content of AI requests and responses — system prompts, messages, and tool-call arguments — for sensitive data such as credit cards, national identifiers, and API keys, applying a per-rule action (mask, block, or log). Detection runs entirely inside the gateway; streaming responses are scanned as they stream (or collected and scanned whole with `streaming.mode: "buffer"`).
|
|
371
372
|
* @public
|
|
372
373
|
*/
|
|
373
374
|
export declare interface AIGatewayDlpInboundPolicyOptions {
|
|
374
375
|
rules: DlpRules;
|
|
375
376
|
/**
|
|
376
|
-
* Your own
|
|
377
|
+
* Your own detectors: a `name`, a regex `pattern`, and optional `context` words. A detector does nothing by itself — activate it by name inside `rules.inbound` or `rules.outbound`, exactly like a built-in type, with its own action, detection level, and mask per direction.
|
|
377
378
|
*/
|
|
378
379
|
customRules?: DlpCustomRule[];
|
|
379
380
|
/**
|
|
@@ -4861,7 +4862,7 @@ declare interface DlpCustomPattern_2 {
|
|
|
4861
4862
|
|
|
4862
4863
|
declare interface DlpCustomRule {
|
|
4863
4864
|
/**
|
|
4864
|
-
*
|
|
4865
|
+
* The detector's name — the key you use to activate it inside `rules.inbound` or `rules.outbound`, exactly like a built-in type id. Must be distinct and must not reuse a built-in type id or group selector.
|
|
4865
4866
|
*/
|
|
4866
4867
|
name: string;
|
|
4867
4868
|
/**
|
|
@@ -4869,68 +4870,16 @@ declare interface DlpCustomRule {
|
|
|
4869
4870
|
*/
|
|
4870
4871
|
pattern: string;
|
|
4871
4872
|
/**
|
|
4872
|
-
* Context words for this
|
|
4873
|
+
* Context words for this detector. An activation with `detection: "corroborated"` then only fires when one of these words appears near the match.
|
|
4873
4874
|
*/
|
|
4874
4875
|
context?: string[];
|
|
4875
|
-
/**
|
|
4876
|
-
* What happens when this rule matches, in BOTH directions. `mask` replaces the matched text with a placeholder and the conversation continues; `block` rejects the request or terminates the response with an error naming only the rule's name (never the values); `log` records a finding and lets the traffic pass unchanged; `off` disables the rule. A rule states either `action` or the directional pair (`inboundAction`/`outboundAction`), never both.
|
|
4877
|
-
*/
|
|
4878
|
-
action?: "mask" | "block" | "log" | "off";
|
|
4879
|
-
/**
|
|
4880
|
-
* What happens when this rule matches in what callers send the model. Use with `outboundAction` to give the rule different behavior per direction. Omitting it (or `off`) leaves the inbound direction unscanned for this rule. Cannot be combined with `action`.
|
|
4881
|
-
*/
|
|
4882
|
-
inboundAction?: "mask" | "block" | "log" | "off";
|
|
4883
|
-
/**
|
|
4884
|
-
* What happens when this rule matches in what the model sends back. Omitting it (or `off`) leaves the outbound direction unscanned for this rule. Cannot be combined with `action`.
|
|
4885
|
-
*/
|
|
4886
|
-
outboundAction?: "mask" | "block" | "log" | "off";
|
|
4887
|
-
/**
|
|
4888
|
-
* How much evidence a match needs before this rule acts. `corroborated` additionally requires one of the type's context words near the match (types that define no context words behave as `standard`); `standard` uses the catalog as tuned — distinctive shapes act on their own while ambiguous shapes need nearby context; `aggressive` counts every pattern match and is false-positive-prone — pair it with the `log` action for audits. Overrides the policy-level `detection` for this rule.
|
|
4889
|
-
*/
|
|
4890
|
-
detection?: "corroborated" | "standard" | "aggressive";
|
|
4891
|
-
/**
|
|
4892
|
-
* Replacement text for this rule's masked matches. The `{type}` token inserts the detected type id in UPPER_SNAKE form, so the default turns a matched email into `[CONTACT_EMAIL]` — typed placeholders keep masked conversations legible to the model. Set a literal like `[REDACTED]` to hide the type.
|
|
4893
|
-
*/
|
|
4894
|
-
mask?: string;
|
|
4895
|
-
partialMask?: DlpPartialMask;
|
|
4896
|
-
}
|
|
4897
|
-
|
|
4898
|
-
declare interface DlpPartialMask {
|
|
4899
|
-
/**
|
|
4900
|
-
* Keep the last N characters of the matched value unmasked and replace the rest with `*`, preserving length (for example `**** **** **** 4242`). Values no longer than N characters are fully masked.
|
|
4901
|
-
*/
|
|
4902
|
-
keepLast: number;
|
|
4903
|
-
}
|
|
4904
|
-
|
|
4905
|
-
declare interface DlpRule {
|
|
4906
|
-
/**
|
|
4907
|
-
* What happens when this type is found, in BOTH directions. `mask` replaces the matched text with a placeholder and the conversation continues; `block` rejects the request or terminates the response with an error naming only the detected types (never the values); `log` records a finding and lets the traffic pass unchanged — use it to trial a rule before enforcing it; `off` excludes this type from a group enabled by a broader key. A rule states either `action` or the directional pair (`inboundAction`/`outboundAction`), never both.
|
|
4908
|
-
*/
|
|
4909
|
-
action?: "mask" | "block" | "log" | "off";
|
|
4910
|
-
/**
|
|
4911
|
-
* What happens when this type is found in what callers send the model (system prompt, message text, and tool-call arguments). Use with `outboundAction` to give one type different behavior per direction — for example mask PII on the way in and block it on the way out. Omitting it (or `off`) leaves the inbound direction unscanned for this type. Cannot be combined with `action`.
|
|
4912
|
-
*/
|
|
4913
|
-
inboundAction?: "mask" | "block" | "log" | "off";
|
|
4914
|
-
/**
|
|
4915
|
-
* What happens when this type is found in what the model sends back (buffered responses whole, streaming responses as they stream). Omitting it (or `off`) leaves the outbound direction unscanned for this type. Cannot be combined with `action`.
|
|
4916
|
-
*/
|
|
4917
|
-
outboundAction?: "mask" | "block" | "log" | "off";
|
|
4918
|
-
/**
|
|
4919
|
-
* How much evidence a match needs before this rule acts. `corroborated` additionally requires one of the type's context words near the match (types that define no context words behave as `standard`); `standard` uses the catalog as tuned — distinctive shapes act on their own while ambiguous shapes need nearby context; `aggressive` counts every pattern match and is false-positive-prone — pair it with the `log` action for audits. Overrides the policy-level `detection` for this rule.
|
|
4920
|
-
*/
|
|
4921
|
-
detection?: "corroborated" | "standard" | "aggressive";
|
|
4922
|
-
/**
|
|
4923
|
-
* Replacement text for this rule's masked matches. The `{type}` token inserts the detected type id in UPPER_SNAKE form, so the default turns a matched email into `[CONTACT_EMAIL]` — typed placeholders keep masked conversations legible to the model. Set a literal like `[REDACTED]` to hide the type.
|
|
4924
|
-
*/
|
|
4925
|
-
mask?: string;
|
|
4926
|
-
partialMask?: DlpPartialMask;
|
|
4927
4876
|
}
|
|
4928
4877
|
|
|
4929
4878
|
/**
|
|
4930
|
-
* What to find and what to do about it. Each key is a built-in data type id (like `id-us-ssn`)
|
|
4879
|
+
* What to find in this direction and what to do about it. Each key is a built-in data type id (like `id-us-ssn`), a group selector (like `pii` or `secret`, plus any dash-aligned id prefix such as `secret-aws`), or one of your custom detectors by name; each value is a rule object whose required `action` says what happens on a match. Types you do not mention are not scanned in this direction. The most specific key wins — an exact id beats a prefix beats a group — and the winning entry decides everything for its type in this direction. When one stretch of text matches multiple rules, the severest action wins (block > mask > log).
|
|
4931
4880
|
* @public
|
|
4932
4881
|
*/
|
|
4933
|
-
declare interface
|
|
4882
|
+
declare interface DlpDirectionRules {
|
|
4934
4883
|
contact?: DlpRule;
|
|
4935
4884
|
finance?: DlpRule;
|
|
4936
4885
|
"finance-us"?: DlpRule;
|
|
@@ -5014,23 +4963,56 @@ declare interface DlpRules {
|
|
|
5014
4963
|
"secret-terraform"?: DlpRule;
|
|
5015
4964
|
"secret-twilio"?: DlpRule;
|
|
5016
4965
|
"secret-zuplo"?: DlpRule;
|
|
4966
|
+
[k: string]: unknown;
|
|
4967
|
+
}
|
|
4968
|
+
|
|
4969
|
+
declare interface DlpPartialMask {
|
|
4970
|
+
/**
|
|
4971
|
+
* Keep the last N characters of the matched value unmasked and replace the rest with `*`, preserving length (for example `**** **** **** 4242`). Values no longer than N characters are fully masked.
|
|
4972
|
+
*/
|
|
4973
|
+
keepLast: number;
|
|
4974
|
+
}
|
|
4975
|
+
|
|
4976
|
+
declare interface DlpRule {
|
|
4977
|
+
/**
|
|
4978
|
+
* What happens when this rule matches in this direction. `mask` replaces the matched text with a placeholder and the conversation continues; `block` rejects the request or terminates the response with an error naming only the detected types (never the values); `log` records a finding and lets the traffic pass unchanged — use it to trial a rule before enforcing it; `off` excludes this type from a group enabled by a broader key in the same section.
|
|
4979
|
+
*/
|
|
4980
|
+
action: "mask" | "block" | "log" | "off";
|
|
4981
|
+
/**
|
|
4982
|
+
* How much evidence a match needs before this rule acts. `corroborated` additionally requires one of the type's context words near the match (types that define no context words behave as `standard`); `standard` uses the catalog as tuned — distinctive shapes act on their own while ambiguous shapes need nearby context; `aggressive` counts every pattern match and is false-positive-prone — pair it with the `log` action for audits. Overrides the policy-level `detection` for this rule.
|
|
4983
|
+
*/
|
|
4984
|
+
detection?: "corroborated" | "standard" | "aggressive";
|
|
4985
|
+
/**
|
|
4986
|
+
* Replacement text for this rule's masked matches. The `{type}` token inserts the detected type id in UPPER_SNAKE form, so the default turns a matched email into `[CONTACT_EMAIL]` — typed placeholders keep masked conversations legible to the model. Set a literal like `[REDACTED]` to hide the type.
|
|
4987
|
+
*/
|
|
4988
|
+
mask?: string;
|
|
4989
|
+
partialMask?: DlpPartialMask;
|
|
5017
4990
|
}
|
|
5018
4991
|
|
|
5019
4992
|
/**
|
|
5020
|
-
*
|
|
4993
|
+
* The scan configuration, split by direction: `inbound` covers what callers send the model (system prompt, message text, and tool-call arguments); `outbound` covers what the model sends back (buffered responses whole, streaming responses as they stream). Each direction you include is scanned; each you omit is left untouched — there is no "both" shorthand and no mirroring, so wanting the same behavior on both sides means stating it in both sections. At least one section must enable at least one rule.
|
|
4994
|
+
* @public
|
|
4995
|
+
*/
|
|
4996
|
+
declare interface DlpRules {
|
|
4997
|
+
inbound?: DlpDirectionRules;
|
|
4998
|
+
outbound?: DlpDirectionRules;
|
|
4999
|
+
}
|
|
5000
|
+
|
|
5001
|
+
/**
|
|
5002
|
+
* How streaming (SSE) responses are inspected. `stream` (the default) scans deltas as they flow, holding each chunk until the boundary scan that includes its successor passes — values split across chunks stay maskable at the cost of one chunk of latency. `buffer` collects the entire response and scans it once as one document — exact detection for values of any length, and a blocked response is a clean 400 because nothing has been delivered yet — at the cost of the client waiting for the full generation. `off` passes streaming responses through unscanned.
|
|
5021
5003
|
* @public
|
|
5022
5004
|
*/
|
|
5023
5005
|
declare interface DlpStreamingSettings {
|
|
5024
5006
|
/**
|
|
5025
|
-
*
|
|
5007
|
+
* `stream` scans deltas in flight with the windowed scanner. `buffer` holds the entire response and scans it once, exactly like a non-streaming response: values of any length are caught (no carry window) and a block is a native 400 error instead of a mid-stream termination, but the client receives nothing until the model finishes. `off` skips scanning of streaming responses entirely, even when rules cover the outbound direction.
|
|
5026
5008
|
*/
|
|
5027
|
-
|
|
5009
|
+
mode?: "stream" | "buffer" | "off";
|
|
5028
5010
|
/**
|
|
5029
|
-
* Scan across chunk boundaries using a carried tail of already-scanned text. When false, each chunk is scanned alone and released immediately — lower cost, but values split across two chunks are missed.
|
|
5011
|
+
* Scan across chunk boundaries using a carried tail of already-scanned text. When false, each chunk is scanned alone and released immediately — lower cost, but values split across two chunks are missed. Applies to `stream` mode only.
|
|
5030
5012
|
*/
|
|
5031
5013
|
boundaryScan?: boolean;
|
|
5032
5014
|
/**
|
|
5033
|
-
* How many trailing characters are carried from one chunk into the next boundary scan. Bounds memory and re-scan cost; must be larger than the longest value you need to catch.
|
|
5015
|
+
* How many trailing characters are carried from one chunk into the next boundary scan. Bounds memory and re-scan cost; must be larger than the longest value you need to catch. Applies to `stream` mode only — `buffer` mode always scans the complete text.
|
|
5034
5016
|
*/
|
|
5035
5017
|
maxCarryChars?: number;
|
|
5036
5018
|
}
|
|
@@ -15679,12 +15661,69 @@ export declare class ZuploMcpSdk {
|
|
|
15679
15661
|
*/
|
|
15680
15662
|
getRawCallToolRequest(): CallToolRequest | null;
|
|
15681
15663
|
/**
|
|
15682
|
-
*
|
|
15683
|
-
*
|
|
15664
|
+
* Overrides fields of the MCP tool result the gateway is about to send.
|
|
15665
|
+
*
|
|
15666
|
+
* Every field is independently optional; an absent field keeps the value
|
|
15667
|
+
* the gateway derives from the downstream response. The most useful
|
|
15668
|
+
* combination is `content` alone: the human-readable summary replaces the
|
|
15669
|
+
* raw serialized body while `structuredContent` is still auto-derived from
|
|
15670
|
+
* it — one call, compact model context, full data preserved.
|
|
15671
|
+
*
|
|
15672
|
+
* @example A compact summary for the model, full JSON in structuredContent
|
|
15673
|
+
* ```ts
|
|
15674
|
+
* const response = await context.invokeRoute("/todos");
|
|
15675
|
+
* new ZuploMcpSdk(context).setRawCallToolResult({
|
|
15676
|
+
* content: [{ type: "text", text: "Fetched the todo list" }],
|
|
15677
|
+
* });
|
|
15678
|
+
* return response;
|
|
15679
|
+
* ```
|
|
15680
|
+
*
|
|
15681
|
+
* Notes:
|
|
15682
|
+
*
|
|
15683
|
+
* - The stored value is *consumed* when the gateway builds the tool result
|
|
15684
|
+
* (asymmetric with {@link getRawCallToolRequest}, which can be read any
|
|
15685
|
+
* number of times).
|
|
15686
|
+
* - The value is written to the context that carried the matching
|
|
15687
|
+
* `tools/call` request, which is looked up exactly one `invokeRoute`
|
|
15688
|
+
* generation up. Calling this from a grandchild invocation (a route that
|
|
15689
|
+
* itself invokes another route) silently stores the override where the
|
|
15690
|
+
* gateway never reads it.
|
|
15691
|
+
* - `isError` is deliberately not overridable: it follows the status of the
|
|
15692
|
+
* response your handler returns, so upstream failures cannot be masked.
|
|
15693
|
+
* - `structuredContent` must be a JSON object. The MCP 2025-11-25 wire
|
|
15694
|
+
* format rejects arrays and scalars here.
|
|
15695
|
+
* - Declining the spec's backwards-compatibility SHOULD (mirroring
|
|
15696
|
+
* serialized JSON into a text block) has a concrete cost: clients that
|
|
15697
|
+
* predate `structuredContent` see only your summary in `content`.
|
|
15698
|
+
* - MCP reserves `_meta` keys with the `modelcontextprotocol.io/` prefix
|
|
15699
|
+
* for the protocol itself; use your own prefix for application metadata.
|
|
15684
15700
|
*
|
|
15685
|
-
* @param
|
|
15701
|
+
* @param result - The fields to override on the tool result
|
|
15702
|
+
*/
|
|
15703
|
+
setRawCallToolResult(result: ZuploMcpToolResultOverride): void;
|
|
15704
|
+
}
|
|
15705
|
+
|
|
15706
|
+
/**
|
|
15707
|
+
* The subset of a `tools/call` result a module author may override via
|
|
15708
|
+
* {@link ZuploMcpSdk.setRawCallToolResult}. Every field is independently
|
|
15709
|
+
* optional; an absent field keeps the value the gateway derives from the
|
|
15710
|
+
* downstream response.
|
|
15711
|
+
*/
|
|
15712
|
+
export declare interface ZuploMcpToolResultOverride {
|
|
15713
|
+
/**
|
|
15714
|
+
* Content blocks for the model to read. Replaces the gateway's default
|
|
15715
|
+
* (the serialized downstream body in a single text block).
|
|
15716
|
+
*/
|
|
15717
|
+
content?: CallToolResult["content"];
|
|
15718
|
+
/**
|
|
15719
|
+
* The structured form of the tool's output. MUST be a JSON object — the
|
|
15720
|
+
* MCP 2025-11-25 wire format rejects arrays/strings/numbers here.
|
|
15721
|
+
*/
|
|
15722
|
+
structuredContent?: Record<string, unknown>;
|
|
15723
|
+
/**
|
|
15724
|
+
* Per-call metadata. Replaces the gateway's default of `{}`.
|
|
15686
15725
|
*/
|
|
15687
|
-
|
|
15726
|
+
_meta?: Record<string, unknown>;
|
|
15688
15727
|
}
|
|
15689
15728
|
|
|
15690
15729
|
/**
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* negotiator
|
|
3
|
+
* Copyright(c) 2026 Blake Embrey
|
|
4
|
+
* MIT Licensed
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
var contentType = require('content-type');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Module exports.
|
|
13
|
+
* @private
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
module.exports = parseAccept;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Parse an Accept-style header.
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
function parseAccept(header) {
|
|
24
|
+
var values = [];
|
|
25
|
+
var index = 0;
|
|
26
|
+
|
|
27
|
+
while (index < header.length) {
|
|
28
|
+
var start = skipOptionalWhitespace(header, index);
|
|
29
|
+
var parsed = contentType.parse(header, { comma: true, start: start });
|
|
30
|
+
|
|
31
|
+
// `content-type` normalizes the type, but accept methods return original casing.
|
|
32
|
+
parsed.type = header.slice(start, start + parsed.type.length);
|
|
33
|
+
values.push(parsed);
|
|
34
|
+
|
|
35
|
+
index = parsed.index + 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return values;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Skip optional whitespace.
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
function skipOptionalWhitespace(header, index) {
|
|
47
|
+
var cursor = index;
|
|
48
|
+
|
|
49
|
+
while (header.charCodeAt(cursor) === 0x20 || header.charCodeAt(cursor) === 0x09) {
|
|
50
|
+
cursor++;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return cursor;
|
|
54
|
+
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
+
var parseAccept = require('./accept');
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Module exports.
|
|
13
15
|
* @public
|
|
@@ -21,55 +23,29 @@ module.exports.preferredCharsets = preferredCharsets;
|
|
|
21
23
|
* @private
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
|
-
var simpleCharsetRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Parse the Accept-Charset header.
|
|
28
|
-
* @private
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
26
|
function parseAcceptCharset(accept) {
|
|
32
|
-
var accepts = accept
|
|
27
|
+
var accepts = parseAccept(accept);
|
|
33
28
|
|
|
34
29
|
for (var i = 0, j = 0; i < accepts.length; i++) {
|
|
35
|
-
var charset =
|
|
36
|
-
|
|
37
|
-
if (charset) {
|
|
38
|
-
accepts[j++] = charset;
|
|
39
|
-
}
|
|
30
|
+
var charset = formatCharset(accepts[i], i);
|
|
31
|
+
if (charset) accepts[j++] = charset;
|
|
40
32
|
}
|
|
41
33
|
|
|
42
|
-
// trim accepts
|
|
43
34
|
accepts.length = j;
|
|
44
|
-
|
|
45
35
|
return accepts;
|
|
46
36
|
}
|
|
47
37
|
|
|
48
38
|
/**
|
|
49
|
-
*
|
|
39
|
+
* Format a parsed charset for negotiation.
|
|
50
40
|
* @private
|
|
51
41
|
*/
|
|
52
42
|
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
if (!match) return null;
|
|
56
|
-
|
|
57
|
-
var charset = match[1];
|
|
58
|
-
var q = 1;
|
|
59
|
-
if (match[2]) {
|
|
60
|
-
var params = match[2].split(';')
|
|
61
|
-
for (var j = 0; j < params.length; j++) {
|
|
62
|
-
var p = params[j].trim().split('=');
|
|
63
|
-
if (p[0] === 'q') {
|
|
64
|
-
q = parseFloat(p[1]);
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
43
|
+
function formatCharset(parsed, i) {
|
|
44
|
+
if (!parsed.type) return null;
|
|
69
45
|
|
|
70
46
|
return {
|
|
71
|
-
charset:
|
|
72
|
-
q: q,
|
|
47
|
+
charset: parsed.type,
|
|
48
|
+
q: parsed.parameters.q ? parseFloat(parsed.parameters.q) : 1,
|
|
73
49
|
i: i
|
|
74
50
|
};
|
|
75
51
|
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
+
var parseAccept = require('./accept');
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Module exports.
|
|
13
15
|
* @public
|
|
@@ -21,20 +23,13 @@ module.exports.preferredEncodings = preferredEncodings;
|
|
|
21
23
|
* @private
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
|
-
var simpleEncodingRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Parse the Accept-Encoding header.
|
|
28
|
-
* @private
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
26
|
function parseAcceptEncoding(accept) {
|
|
32
|
-
var accepts = accept
|
|
27
|
+
var accepts = parseAccept(accept);
|
|
33
28
|
var hasIdentity = false;
|
|
34
29
|
var minQuality = 1;
|
|
35
30
|
|
|
36
31
|
for (var i = 0, j = 0; i < accepts.length; i++) {
|
|
37
|
-
var encoding =
|
|
32
|
+
var encoding = formatEncoding(accepts[i], i);
|
|
38
33
|
|
|
39
34
|
if (encoding) {
|
|
40
35
|
accepts[j++] = encoding;
|
|
@@ -55,37 +50,21 @@ function parseAcceptEncoding(accept) {
|
|
|
55
50
|
};
|
|
56
51
|
}
|
|
57
52
|
|
|
58
|
-
// trim accepts
|
|
59
53
|
accepts.length = j;
|
|
60
|
-
|
|
61
54
|
return accepts;
|
|
62
55
|
}
|
|
63
56
|
|
|
64
57
|
/**
|
|
65
|
-
*
|
|
58
|
+
* Format a parsed encoding for negotiation.
|
|
66
59
|
* @private
|
|
67
60
|
*/
|
|
68
61
|
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
if (!match) return null;
|
|
72
|
-
|
|
73
|
-
var encoding = match[1];
|
|
74
|
-
var q = 1;
|
|
75
|
-
if (match[2]) {
|
|
76
|
-
var params = match[2].split(';');
|
|
77
|
-
for (var j = 0; j < params.length; j++) {
|
|
78
|
-
var p = params[j].trim().split('=');
|
|
79
|
-
if (p[0] === 'q') {
|
|
80
|
-
q = parseFloat(p[1]);
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
62
|
+
function formatEncoding(parsed, i) {
|
|
63
|
+
if (!parsed.type) return null;
|
|
85
64
|
|
|
86
65
|
return {
|
|
87
|
-
encoding:
|
|
88
|
-
q: q,
|
|
66
|
+
encoding: parsed.type,
|
|
67
|
+
q: parsed.parameters.q ? parseFloat(parsed.parameters.q) : 1,
|
|
89
68
|
i: i
|
|
90
69
|
};
|
|
91
70
|
}
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
+
var contentType = require('content-type');
|
|
12
|
+
var parseAccept = require('./accept');
|
|
13
|
+
|
|
11
14
|
/**
|
|
12
15
|
* Module exports.
|
|
13
16
|
* @public
|
|
@@ -21,60 +24,36 @@ module.exports.preferredLanguages = preferredLanguages;
|
|
|
21
24
|
* @private
|
|
22
25
|
*/
|
|
23
26
|
|
|
24
|
-
var simpleLanguageRegExp = /^\s*([^\s\-;]+)(?:-([^\s;]+))?\s*(?:;(.*))?$/;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Parse the Accept-Language header.
|
|
28
|
-
* @private
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
27
|
function parseAcceptLanguage(accept) {
|
|
32
|
-
var accepts = accept
|
|
28
|
+
var accepts = parseAccept(accept);
|
|
33
29
|
|
|
34
30
|
for (var i = 0, j = 0; i < accepts.length; i++) {
|
|
35
|
-
var language =
|
|
36
|
-
|
|
37
|
-
if (language) {
|
|
38
|
-
accepts[j++] = language;
|
|
39
|
-
}
|
|
31
|
+
var language = formatLanguage(accepts[i], i);
|
|
32
|
+
if (language) accepts[j++] = language;
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
// trim accepts
|
|
43
35
|
accepts.length = j;
|
|
44
|
-
|
|
45
36
|
return accepts;
|
|
46
37
|
}
|
|
47
38
|
|
|
48
39
|
/**
|
|
49
|
-
*
|
|
40
|
+
* Format a parsed language for negotiation.
|
|
50
41
|
* @private
|
|
51
42
|
*/
|
|
52
43
|
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
if (!match) return null;
|
|
56
|
-
|
|
57
|
-
var prefix = match[1]
|
|
58
|
-
var suffix = match[2]
|
|
59
|
-
var full = prefix
|
|
44
|
+
function formatLanguage(parsed, i) {
|
|
45
|
+
if (!parsed.type) return null;
|
|
60
46
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
var
|
|
64
|
-
if (match[3]) {
|
|
65
|
-
var params = match[3].split(';')
|
|
66
|
-
for (var j = 0; j < params.length; j++) {
|
|
67
|
-
var p = params[j].split('=');
|
|
68
|
-
if (p[0] === 'q') q = parseFloat(p[1]);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
47
|
+
var hyphen = parsed.type.indexOf('-');
|
|
48
|
+
var prefix = hyphen === -1 ? parsed.type : parsed.type.slice(0, hyphen);
|
|
49
|
+
var suffix = hyphen === -1 ? undefined : parsed.type.slice(hyphen + 1);
|
|
71
50
|
|
|
72
51
|
return {
|
|
73
52
|
prefix: prefix,
|
|
74
53
|
suffix: suffix,
|
|
75
|
-
q: q,
|
|
54
|
+
q: parsed.parameters.q ? parseFloat(parsed.parameters.q) : 1,
|
|
76
55
|
i: i,
|
|
77
|
-
full:
|
|
56
|
+
full: parsed.type
|
|
78
57
|
};
|
|
79
58
|
}
|
|
80
59
|
|
|
@@ -103,7 +82,7 @@ function getLanguagePriority(language, accepted, index) {
|
|
|
103
82
|
*/
|
|
104
83
|
|
|
105
84
|
function specify(language, spec, index) {
|
|
106
|
-
var p =
|
|
85
|
+
var p = formatLanguage(contentType.parse(language), 0)
|
|
107
86
|
if (!p) return null;
|
|
108
87
|
var s = 0;
|
|
109
88
|
if(spec.full.toLowerCase() === p.full.toLowerCase()){
|