@zuplo/cli 7.4.1 → 7.4.4

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.
Files changed (88) hide show
  1. package/node_modules/@inquirer/checkbox/package.json +5 -4
  2. package/node_modules/@inquirer/confirm/dist/index.d.ts +1 -1
  3. package/node_modules/@inquirer/confirm/package.json +4 -3
  4. package/node_modules/@inquirer/core/README.md +9 -3
  5. package/node_modules/@inquirer/core/dist/lib/hook-engine.d.ts +2 -8
  6. package/node_modules/@inquirer/core/dist/lib/use-memo.js +1 -1
  7. package/node_modules/@inquirer/core/dist/lib/use-state.d.ts +5 -2
  8. package/node_modules/@inquirer/core/dist/lib/use-state.js +7 -2
  9. package/node_modules/@inquirer/core/package.json +5 -4
  10. package/node_modules/@inquirer/editor/dist/index.d.ts +1 -1
  11. package/node_modules/@inquirer/editor/package.json +5 -4
  12. package/node_modules/@inquirer/expand/README.md +1 -1
  13. package/node_modules/@inquirer/expand/package.json +4 -3
  14. package/node_modules/@inquirer/external-editor/README.md +13 -0
  15. package/node_modules/@inquirer/external-editor/package.json +4 -3
  16. package/node_modules/@inquirer/figures/package.json +4 -3
  17. package/node_modules/@inquirer/input/package.json +4 -3
  18. package/node_modules/@inquirer/number/dist/index.d.ts +1 -1
  19. package/node_modules/@inquirer/number/dist/index.js +1 -6
  20. package/node_modules/@inquirer/number/dist/is-step-of.d.ts +1 -0
  21. package/node_modules/@inquirer/number/dist/is-step-of.js +22 -0
  22. package/node_modules/@inquirer/number/package.json +4 -3
  23. package/node_modules/@inquirer/password/package.json +4 -3
  24. package/node_modules/@inquirer/rawlist/package.json +4 -3
  25. package/node_modules/@inquirer/search/README.md +9 -8
  26. package/node_modules/@inquirer/search/dist/index.d.ts +1 -0
  27. package/node_modules/@inquirer/search/dist/index.js +6 -1
  28. package/node_modules/@inquirer/search/package.json +5 -4
  29. package/node_modules/@inquirer/select/package.json +5 -4
  30. package/node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.d.ts.map +1 -1
  31. package/node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.js +4 -2
  32. package/node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.mjs +4 -2
  33. package/node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.d.ts.map +1 -1
  34. package/node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.js +5 -5
  35. package/node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.mjs +5 -5
  36. package/node_modules/@posthog/core/dist/error-tracking/parsers/base.d.ts.map +1 -1
  37. package/node_modules/@posthog/core/dist/error-tracking/parsers/base.js +2 -1
  38. package/node_modules/@posthog/core/dist/error-tracking/parsers/base.mjs +2 -1
  39. package/node_modules/@posthog/core/dist/posthog-core.d.ts.map +1 -1
  40. package/node_modules/@posthog/core/dist/posthog-core.js +1 -0
  41. package/node_modules/@posthog/core/dist/posthog-core.mjs +1 -0
  42. package/node_modules/@posthog/core/package.json +1 -1
  43. package/node_modules/@posthog/core/src/error-tracking/coercers/error-coercer.ts +8 -2
  44. package/node_modules/@posthog/core/src/error-tracking/coercers/error-event-coercer.spec.ts +33 -0
  45. package/node_modules/@posthog/core/src/error-tracking/coercers/error-event-coercer.ts +13 -6
  46. package/node_modules/@posthog/core/src/error-tracking/error-properties-builder.coerce.spec.ts +15 -0
  47. package/node_modules/@posthog/core/src/error-tracking/parsers/base.spec.ts +34 -0
  48. package/node_modules/@posthog/core/src/error-tracking/parsers/base.ts +10 -2
  49. package/node_modules/@posthog/core/src/posthog-core.ts +1 -0
  50. package/node_modules/@zuplo/core/customer.cli.minified.js +239 -239
  51. package/node_modules/@zuplo/core/index.minified.js +253 -253
  52. package/node_modules/@zuplo/core/package.json +1 -1
  53. package/node_modules/@zuplo/graphql/package.json +1 -1
  54. package/node_modules/@zuplo/openapi-tools/package.json +1 -1
  55. package/node_modules/@zuplo/otel/package.json +1 -1
  56. package/node_modules/@zuplo/runtime/out/esm/chunk-4SX4HBWT.js +409 -0
  57. package/node_modules/@zuplo/runtime/out/esm/chunk-4SX4HBWT.js.map +1 -0
  58. package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
  59. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +13 -13
  60. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js.map +1 -1
  61. package/node_modules/@zuplo/runtime/out/types/index.d.ts +61 -4
  62. package/node_modules/@zuplo/runtime/out/types/mcp-gateway/index.d.ts +39 -2
  63. package/node_modules/@zuplo/runtime/package.json +1 -1
  64. package/node_modules/negotiator/lib/accept.js +54 -0
  65. package/node_modules/negotiator/lib/charset.js +10 -34
  66. package/node_modules/negotiator/lib/encoding.js +9 -30
  67. package/node_modules/negotiator/lib/language.js +15 -36
  68. package/node_modules/negotiator/lib/mediaType.js +16 -134
  69. package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
  70. package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
  71. package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
  72. package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
  73. package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
  74. package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
  75. package/node_modules/negotiator/package.json +16 -10
  76. package/package.json +11 -11
  77. package/node_modules/@inquirer/external-editor/dist/errors/CreateFileError.d.ts +0 -10
  78. package/node_modules/@inquirer/external-editor/dist/errors/CreateFileError.js +0 -13
  79. package/node_modules/@inquirer/external-editor/dist/errors/LaunchEditorError.d.ts +0 -10
  80. package/node_modules/@inquirer/external-editor/dist/errors/LaunchEditorError.js +0 -13
  81. package/node_modules/@inquirer/external-editor/dist/errors/ReadFileError.d.ts +0 -10
  82. package/node_modules/@inquirer/external-editor/dist/errors/ReadFileError.js +0 -13
  83. package/node_modules/@inquirer/external-editor/dist/errors/RemoveFileError.d.ts +0 -10
  84. package/node_modules/@inquirer/external-editor/dist/errors/RemoveFileError.js +0 -13
  85. package/node_modules/@zuplo/runtime/out/esm/chunk-JKIKT5LB.js +0 -409
  86. package/node_modules/@zuplo/runtime/out/esm/chunk-JKIKT5LB.js.map +0 -1
  87. package/node_modules/negotiator/HISTORY.md +0 -114
  88. /package/node_modules/@zuplo/runtime/out/esm/{chunk-JKIKT5LB.js.LEGAL.txt → chunk-4SX4HBWT.js.LEGAL.txt} +0 -0
@@ -15661,12 +15661,69 @@ export declare class ZuploMcpSdk {
15661
15661
  */
15662
15662
  getRawCallToolRequest(): CallToolRequest | null;
15663
15663
  /**
15664
- * Sets the MCP request/response context object.
15665
- * Use this to set `_meta` that should be included in the tool result.
15664
+ * Overrides fields of the MCP tool result the gateway is about to send.
15666
15665
  *
15667
- * @param req - The object containing metadata (e.g. `{ _meta: { ... } }`)
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.
15700
+ *
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 `{}`.
15668
15725
  */
15669
- setRawCallToolResult(req: CallToolResult): void;
15726
+ _meta?: Record<string, unknown>;
15670
15727
  }
15671
15728
 
15672
15729
  /**
@@ -1759,8 +1759,11 @@ export declare interface McpEntraOAuthInboundPolicyOptions {
1759
1759
  /**
1760
1760
  * Activates the MCP Gateway internal routes (OAuth authorization server,
1761
1761
  * upstream connection management, well-known metadata) on the runtime router.
1762
- * When no MCP-related policy is present the plugin registers no routes; it
1763
- * still records `plugin.mcp-gateway` feature usage on construction so gateway
1762
+ * It also serves a read-only MCP Server Registry API (v0.1) advertising the
1763
+ * gateway's MCP routes — mounted at `/__zuplo/mcp-registry` by default and
1764
+ * configurable or disableable via the `registry` option. When no MCP-related
1765
+ * policy is present the plugin registers no OAuth routes; it still records
1766
+ * `plugin.mcp-gateway` feature usage on construction so gateway
1764
1767
  * adoption is visible in telemetry regardless of route configuration.
1765
1768
  *
1766
1769
  * Importing from `@zuplo/runtime/mcp-gateway` is the opt-in: the runtime core
@@ -1811,6 +1814,40 @@ export declare interface McpGatewayPluginOptions {
1811
1814
  * @default "/__zuplo"
1812
1815
  */
1813
1816
  basePath?: string;
1817
+ /**
1818
+ * Configures the read-only MCP Server Registry API. Enabled by default;
1819
+ * pass `{ enabled: false }` to turn it off.
1820
+ */
1821
+ registry?: McpGatewayRegistryOptions;
1822
+ }
1823
+
1824
+ /**
1825
+ * Options for the MCP Server Registry API served by the gateway.
1826
+ *
1827
+ * The registry is a read-only MCP Server Registry (v0.1) that advertises the
1828
+ * gateway's own MCP routes, so MCP clients and subregistries can discover
1829
+ * them. Discovery endpoints are unauthenticated per the registry
1830
+ * specification; publishing endpoints respond `501`.
1831
+ *
1832
+ * @beta
1833
+ */
1834
+ export declare interface McpGatewayRegistryOptions {
1835
+ /**
1836
+ * Set to `false` to disable the registry entirely. No registry routes are
1837
+ * registered when disabled.
1838
+ *
1839
+ * @default true
1840
+ */
1841
+ enabled?: boolean;
1842
+ /**
1843
+ * Absolute URL path where the registry API mounts. The registry endpoints
1844
+ * live below this path (e.g. `{path}/v0.1/servers`). Defaults to
1845
+ * `/mcp-registry` under the configured `basePath`, so with the default
1846
+ * `basePath` the registry is served at `/__zuplo/mcp-registry`.
1847
+ *
1848
+ * @default "{basePath}/mcp-registry"
1849
+ */
1850
+ path?: string;
1814
1851
  }
1815
1852
 
1816
1853
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zuplo/runtime",
3
3
  "type": "module",
4
- "version": "7.4.1",
4
+ "version": "7.4.4",
5
5
  "repository": "https://github.com/zuplo/zuplo",
6
6
  "author": "Zuplo, Inc.",
7
7
  "exports": {
@@ -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.split(',');
27
+ var accepts = parseAccept(accept);
33
28
 
34
29
  for (var i = 0, j = 0; i < accepts.length; i++) {
35
- var charset = parseCharset(accepts[i].trim(), i);
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
- * Parse a charset from the Accept-Charset header.
39
+ * Format a parsed charset for negotiation.
50
40
  * @private
51
41
  */
52
42
 
53
- function parseCharset(str, i) {
54
- var match = simpleCharsetRegExp.exec(str);
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: 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.split(',');
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 = parseEncoding(accepts[i].trim(), i);
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
- * Parse an encoding from the Accept-Encoding header.
58
+ * Format a parsed encoding for negotiation.
66
59
  * @private
67
60
  */
68
61
 
69
- function parseEncoding(str, i) {
70
- var match = simpleEncodingRegExp.exec(str);
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: 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.split(',');
28
+ var accepts = parseAccept(accept);
33
29
 
34
30
  for (var i = 0, j = 0; i < accepts.length; i++) {
35
- var language = parseLanguage(accepts[i].trim(), i);
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
- * Parse a language from the Accept-Language header.
40
+ * Format a parsed language for negotiation.
50
41
  * @private
51
42
  */
52
43
 
53
- function parseLanguage(str, i) {
54
- var match = simpleLanguageRegExp.exec(str);
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
- if (suffix) full += "-" + suffix;
62
-
63
- var q = 1;
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: 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 = parseLanguage(language)
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()){
@@ -8,6 +8,9 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ var contentType = require('content-type');
12
+ var parseAcceptHeader = require('./accept');
13
+
11
14
  /**
12
15
  * Module exports.
13
16
  * @public
@@ -21,71 +24,35 @@ module.exports.preferredMediaTypes = preferredMediaTypes;
21
24
  * @private
22
25
  */
23
26
 
24
- var simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/;
25
-
26
- /**
27
- * Parse the Accept header.
28
- * @private
29
- */
30
-
31
27
  function parseAccept(accept) {
32
- var accepts = splitMediaTypes(accept);
28
+ var accepts = parseAcceptHeader(accept);
33
29
 
34
30
  for (var i = 0, j = 0; i < accepts.length; i++) {
35
- var mediaType = parseMediaType(accepts[i].trim(), i);
36
-
37
- if (mediaType) {
38
- accepts[j++] = mediaType;
39
- }
31
+ var mediaType = formatMediaType(accepts[i], i);
32
+ if (mediaType) accepts[j++] = mediaType;
40
33
  }
41
34
 
42
- // trim accepts
43
35
  accepts.length = j;
44
-
45
36
  return accepts;
46
37
  }
47
38
 
48
39
  /**
49
- * Parse a media type from the Accept header.
40
+ * Format a parsed content type for negotiation.
50
41
  * @private
51
42
  */
52
43
 
53
- function parseMediaType(str, i) {
54
- var match = simpleMediaTypeRegExp.exec(str);
55
- if (!match) return null;
56
-
57
- var params = Object.create(null);
58
- var q = 1;
59
- var subtype = match[2];
60
- var type = match[1];
61
-
62
- if (match[3]) {
63
- var kvps = splitParameters(match[3]).map(splitKeyValuePair);
64
-
65
- for (var j = 0; j < kvps.length; j++) {
66
- var pair = kvps[j];
67
- var key = pair[0].toLowerCase();
68
- var val = pair[1];
44
+ function formatMediaType(parsed, i) {
45
+ var slash = parsed.type.indexOf('/');
46
+ if (slash === -1) return null;
69
47
 
70
- // get the value, unwrapping quotes
71
- var value = val && val[0] === '"' && val[val.length - 1] === '"'
72
- ? val.slice(1, -1)
73
- : val;
48
+ var q = parsed.parameters.q ? parseFloat(parsed.parameters.q) : 1;
74
49
 
75
- if (key === 'q') {
76
- q = parseFloat(value);
77
- break;
78
- }
79
-
80
- // store parameter
81
- params[key] = value;
82
- }
83
- }
50
+ delete parsed.parameters.q;
84
51
 
85
52
  return {
86
- type: type,
87
- subtype: subtype,
88
- params: params,
53
+ type: parsed.type.slice(0, slash),
54
+ subtype: parsed.type.slice(slash + 1),
55
+ params: parsed.parameters,
89
56
  q: q,
90
57
  i: i
91
58
  };
@@ -116,7 +83,7 @@ function getMediaTypePriority(type, accepted, index) {
116
83
  */
117
84
 
118
85
  function specify(type, spec, index) {
119
- var p = parseMediaType(type);
86
+ var p = formatMediaType(contentType.parse(type), 0);
120
87
  var s = 0;
121
88
 
122
89
  if (!p) {
@@ -207,88 +174,3 @@ function getFullType(spec) {
207
174
  function isQuality(spec) {
208
175
  return spec.q > 0;
209
176
  }
210
-
211
- /**
212
- * Count the number of quotes in a string.
213
- * @private
214
- */
215
-
216
- function quoteCount(string) {
217
- var count = 0;
218
- var index = 0;
219
-
220
- while ((index = string.indexOf('"', index)) !== -1) {
221
- count++;
222
- index++;
223
- }
224
-
225
- return count;
226
- }
227
-
228
- /**
229
- * Split a key value pair.
230
- * @private
231
- */
232
-
233
- function splitKeyValuePair(str) {
234
- var index = str.indexOf('=');
235
- var key;
236
- var val;
237
-
238
- if (index === -1) {
239
- key = str;
240
- } else {
241
- key = str.slice(0, index);
242
- val = str.slice(index + 1);
243
- }
244
-
245
- return [key, val];
246
- }
247
-
248
- /**
249
- * Split an Accept header into media types.
250
- * @private
251
- */
252
-
253
- function splitMediaTypes(accept) {
254
- var accepts = accept.split(',');
255
-
256
- for (var i = 1, j = 0; i < accepts.length; i++) {
257
- if (quoteCount(accepts[j]) % 2 == 0) {
258
- accepts[++j] = accepts[i];
259
- } else {
260
- accepts[j] += ',' + accepts[i];
261
- }
262
- }
263
-
264
- // trim accepts
265
- accepts.length = j + 1;
266
-
267
- return accepts;
268
- }
269
-
270
- /**
271
- * Split a string of parameters.
272
- * @private
273
- */
274
-
275
- function splitParameters(str) {
276
- var parameters = str.split(';');
277
-
278
- for (var i = 1, j = 0; i < parameters.length; i++) {
279
- if (quoteCount(parameters[j]) % 2 == 0) {
280
- parameters[++j] = parameters[i];
281
- } else {
282
- parameters[j] += ';' + parameters[i];
283
- }
284
- }
285
-
286
- // trim parameters
287
- parameters.length = j + 1;
288
-
289
- for (var i = 0; i < parameters.length; i++) {
290
- parameters[i] = parameters[i].trim();
291
- }
292
-
293
- return parameters;
294
- }
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2015 Douglas Christopher Wilson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.