Skip to content

v0.17.0

Choose a tag to compare

@mikecarroll mikecarroll released this 21 Oct 22:43
· 2 commits to main since this release
1283759

[0.17.0] - 2026-10-21

What's New

  • HelpCenterDocsService reads the Coolhand help center, with no API key required. searchHelpArticles({ query, category, page, perPage }) returns { articles, pagination }, getHelpArticle(slug) returns one article with its markdown body, and listHelpCategories() lists the sections. Coolhand exposes the same three methods and sends its own key; keyless use goes through new HelpCenterDocsService() directly, since the Coolhand constructor requires a key. A key (apiKey, else COOLHAND_API_KEY) is sent as X-API-Key and lifts the anonymous limit of 30 requests per minute per IP; pass apiKey: '' to stay anonymous. A rejected key throws HttpError 401, never an anonymous retry. category is sent as q[help_category_slug_eq] because the endpoint has no category parameter. See docs/help-center.md. (#296, #297)

Upgrade Notes

  • Constructors now throw on an invalid apiKey. new Coolhand(...), direct service construction and initializeGlobalMonitoring throw if the key is empty, whitespace-only, not a string, or contains characters that are not valid in an HTTP header (for example a newline from a bad .env parse). Previously such a key only made requests fail. Surrounding whitespace is trimmed, matching what fetch does. auto-monitor already catches the throw. (#287, #293)
  • http.request('https://…', opts) and https.request('http://…', opts) now throw ERR_INVALID_PROTOCOL, as native Node does. Calls with a mismatched URL scheme and module used to be sent anyway, so code that relied on that must use the matching module. (#289, #295)
  • More requests can now be excluded. excludeApiPatterns also matches the canonical form of each URL, so internal.corp now excludes https://Internal.Corp/v1 and https://internal.corp./, and an example.com/ entry also excludes a bare https://example.com. Nothing that matched before stops matching. Write host entries in lowercase. (#290, #294)

Security

  • Credential parts in raw multipart/form-data request bodies are redacted. Bodies captured through http/https (file and audio uploads) were logged with parts such as name="api_key" unredacted; the fetch + FormData path was already safe. Values of credential-named parts (api_key, password, client_secret, user[password], bare token, ...) are replaced with [REDACTED], recognized by body shape rather than Content-Type; other parts and the multipart framing are untouched. Known gap: a first part with five or more headers before Content-Disposition is not recognized. (#288, #292)
  • excludeApiPatterns can no longer be bypassed by host case, a trailing host dot or an IPv6 literal. Previously https://Internal.Corp/v1 and https://internal.corp./ were logged to Coolhand despite an internal.corp exclusion. (#290, #294)
  • http.request('https://…', opts) no longer sends the request, including its Authorization header, as cleartext HTTP on port 80. The URL-to-options conversion dropped the scheme, so the mismatch never reached Node. (#289, #295)
  • A malformed apiKey is no longer echoed in error messages. undici's Headers.append: "<key>" is an invalid header value used to be printed to stderr and re-thrown to callers. The configured key is now masked as [redacted] in request-error logs, thrown errors and response-body excerpts (BaseService, McpService, ClientFileService, OptimizationFeedbackLinkService), and the raw error is no longer attached as cause when it would still contain the key. (#287, #293)
  • LoggingService's catch-all error log masks the key too. It was the one BaseService subclass error log that skipped the masking above.

Bug Fixes

  • buildURL brackets IPv6 hostnames, so { hostname: '::1', port: 3000 } builds http://[::1]:3000/x instead of an unparseable URL, on both the auto-monitor and Coolhand paths. (#290, #294)
  • A synchronous throw from the real request no longer leaks the dedup entry, so a retried call is still captured. (#289, #295)

Documentation

  • New docs/help-center.md and a short README section for the help center methods. docs/exclude-patterns.md, docs/global-monitoring.md (multipart redaction, apiKey validation) are updated for the changes above. (#296, #297)

Maintenance

  • BaseService takes an opt-in allowAnonymous constructor option so only HelpCenterDocsService can be built without a key, with mask() and the cause-chain check no-ops when there is no key. getJsonWithHeaders omits X-API-Key when the key is empty. (#296, #297)
  • normalizeHostname moved to the new src/utils/url-host.ts (it was never exported from src/index.ts), alongside formatHostForUrl. (#290, #294)