Skip to content

fix: SEO improvements, CI hardening, and lint cleanup#131

Closed
jaysin586 wants to merge 15 commits into
mainfrom
fix/seo-unique-titles
Closed

fix: SEO improvements, CI hardening, and lint cleanup#131
jaysin586 wants to merge 15 commits into
mainfrom
fix/seo-unique-titles

Conversation

@jaysin586

Copy link
Copy Markdown
Contributor

Summary

  • CI: Scope secrets to GitHub Environments (ci / production) to resolve zizmor secrets-outside-env warnings
  • SEO: Trim all 17 meta descriptions exceeding 160 characters (range was 162–185) to resolve Ahrefs Site Audit warnings
  • Lint: Remove unnecessary trunk-ignore(eslint/@typescript-eslint/no-explicit-any) comments in LRU tests (rule not active in test files)
  • Trunk: Add osv-scanner ignore for pnpm-lock.yaml to match other Humanspeak repos
  • Deps: Bump dependencies and trunk plugins

Test plan

  • Verify CI workflows pass with new environment: declarations
  • Confirm meta descriptions render correctly on docs site
  • Run trunk check to verify no remaining lint issues

🤖 Generated with Claude Code

jaysin586 and others added 15 commits March 9, 2026 12:23
- Replace O(n) full-map scan in prune() with FIFO expiration queue
  for O(k) pruning of expired entries
- Move tombstone compaction to a background microtask to keep
  prune() non-blocking
- Add compactionScheduled flag to prevent duplicate microtasks
- Reset queue and flag in clear() for proper cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix critical error: @cached docs falsely claimed per-instance caching;
  all instances actually share one cache per decorated method
- Fix async example generic from Promise<Data> to Data for consistency
- Add missing hooks option to Getting Started config table
- Add getOrSet() subsection to Getting Started quick start

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add --filter . to pnpm install commands in npm-publish and run-tests
workflows to skip docs workspace dependencies that may require a
different Node version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ahrefs site audit flagged 16 pages with meta descriptions too short.
Updated descriptions in both .svx seo.description overrides and
+page.ts fallbacks to 120-170 characters for better search snippets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add --config.engine-strict=false to pnpm install in CI workflows
- Replace softprops/action-gh-release with gh CLI for release creation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update docs-kit, svelte, vite, vitest, wrangler, and other deps
- Refresh sitemap lastmod dates for updated example pages
- Move cf-typegen script to docs package

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aligns with updated cf-typegen script that outputs to docs/src/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bump engines.node from >=18.0.0 to >=20.19.0 (vite@8 + vitest@4 require it)
- Fix async-fetching description: replace "stale-while-revalidate" with
  "thundering herd prevention" to match actual page content
- Fix computed-values description: remove "TTL refresh" since examples use ttl: 0
- Trim monitoring fallback description to <=170 chars
- Fix multi-tenant description to accurately reflect single-cache key-prefix
  approach rather than implying separate cache instances
- Coalesce expirationQueue tail entries on rapid same-key overwrites to
  prevent unbounded queue growth between prune() calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use optional chaining instead of redundant length guard
- Clarify comment: coalescing applies to consecutive same-key overwrites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add `environment: ci` to debug-check and build jobs, and
`environment: production` to publish-github-packages. Resolves
zizmor secrets-outside-env warnings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shorten all 17 meta descriptions that exceeded 160 characters
(range was 162-185). Resolves Ahrefs Site Audit warning.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The no-explicit-any rule is not active in test files, so the
trunk-ignore directives were flagged as doing nothing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 23, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR enhances CI workflows with environment-scoped job execution and engine-strict disabling, updates documentation content and metadata across examples and API references with more detailed descriptions, patches Cloudflare Worker type definitions with Props generics and Stream bindings, and refactors cache expiration handling to use a queue-based tombstone system with conditional microtask compaction instead of scanning all entries.

Changes

Cohort / File(s) Summary
CI/Workflow Configuration
.github/workflows/npm-publish.yml, .github/workflows/run-tests.yml
Updated pnpm install invocations to use --filter . scope and --config.engine-strict=false; added job-level environment settings (ci and production); replaced GitHub Release action with shell script using gh release create.
Linting & Build Tooling
.trunk/trunk.yaml, package.json
Bumped Trunk plugin version to v1.7.6; added sitemap/pnpm-lock ignore rules and osv-scanner disable; updated linter versions (checkov, eslint, trufflehog); raised minimum Node.js engine to >=20.19.0; updated dev dependencies.
Documentation Build Setup
docs/package.json
Added cf-typegen script running wrangler types && mv worker-configuration.d.ts src/; bumped build and runtime dependencies (@humanspeak/docs-kit, Tailwind, Vite, SvelteKit, TypeScript, wrangler).
Documentation Metadata
docs/src/lib/sitemap-manifest.json, docs/src/routes/docs/*/+page.ts, docs/src/routes/examples/*/+page.ts
Updated sitemap timestamps (various docs routes to 2026-03-09 and 2026-03-15); refreshed page load() function descriptions across API docs, examples, and getting-started to include specifics on TTL, LRU, cache keys, hooks, deduplication, and integration patterns.
Documentation Page Content
docs/src/routes/docs/api/cached-decorator/+page.svx, docs/src/routes/docs/examples/**/(+page.svx|+page.ts), docs/src/routes/docs/getting-started/+page.svx
Updated @cached() documentation to clarify shared cross-instance cache; expanded example descriptions (SEO metadata) to mention TTL, eviction, deduplication, monitoring, and multi-tenancy patterns; added new "Using getOrSet()" section and hooks configuration table with lifecycle callbacks (onEvict, onExpire, onSet, onDelete, onClear).
Cloudflare Worker Type Definitions
docs/src/worker-configuration.d.ts
Added generic Props parameter to ExecutionContext and all ExportedHandler* types; updated WebSocket accept() signature and added binaryType property; added Container HTTP interception methods and WorkerLoader.load(); replaced AI Search filter types with VectorizeVectorMetadataFilter; added WorkflowStepContext with attempt field; introduced comprehensive Stream binding types.
Cache Core Implementation
src/cache.ts
Introduced expirationQueue to track { key, timestamp } entries; rewrote prune() to drain expired entries from queue front instead of scanning cache, using timestamp matching to detect and skip tombstones; implemented microtask-based compaction scheduling when queue bloat exceeds 2 * cache.size; updated set() and clear() to manage queue state.
Test Updates
src/cache.lru.test.ts, src/cache.statistics.test.ts
Removed eslint ignore comments in LRU defensive tests; added new prune() test verifying tombstone handling and compaction with repeated key overwrites under TTL.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

documentation, enhancement

Poem

🎯 The queue keeps time with graceful care,
Tombstones shed their weight with flair,
Compaction scheduled, bloat takes flight,
While docs shine bright with fresh insight! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately summarizes the main changes: SEO improvements, CI hardening, and lint cleanup are all major themes across the 40+ modified files.
Description check ✅ Passed Description is well-structured with bullet points covering all major change categories (CI, SEO, Lint, Trunk, Deps) with specific details and a test plan.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Important

Merge conflicts detected (Beta)

  • Resolve merge conflict in branch fix/seo-unique-titles
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/seo-unique-titles

Comment @coderabbitai help to get the list of available commands and usage tips.

@jaysin586 jaysin586 added documentation Improvements or additions to documentation skip-publish This is something important, but we dont want to publish it labels Mar 23, 2026
@jaysin586 jaysin586 self-assigned this Mar 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/src/worker-configuration.d.ts (1)

11487-11494: ⚠️ Potential issue | 🟡 Minor

Document cssSelector before publishing it in the docs surface.

The new option is exposed without any explanation, so users still won’t know what it scopes or how it behaves. Add the JSDoc in the source that feeds this generated file.

Suggested doc fix
     html?: {
         images?: EmbeddedImageConversionOptions & {
             convertOGImage?: boolean;
         };
         hostname?: string;
+        /**
+         * Scope HTML-to-Markdown conversion using this CSS selector.
+         */
         cssSelector?: string;
     };

As per coding guidelines, "docs/**: Documentation site built with SvelteKit. Check for accuracy and clarity."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/worker-configuration.d.ts` around lines 11487 - 11494, Add a JSDoc
comment for the html.cssSelector option on the ConversionOptions type so the
generated docs explain what the selector scopes and how it behaves; locate the
ConversionOptions declaration (the html property under ConversionOptions and the
nested images options where convertOGImage is defined) and add a short JSDoc
describing that cssSelector accepts a CSS selector string used to scope which
elements or parts of the HTML are converted (include examples like "body" or
".article-content"), note whether it accepts multiple selectors, and mention any
sanitize/host/hostname interactions or selector precedence so the docs generator
will surface this explanation.
🧹 Nitpick comments (3)
src/cache.ts (1)

889-892: Consider avoiding splice for better amortized performance.

splice(0, head) is O(n) where n is the remaining queue length. For high-throughput caches with large queues, consider tracking a head index and periodically rebasing instead.

That said, this is likely fine for most use cases since the splice only runs when there are actually expired entries to drain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cache.ts` around lines 889 - 892, The current in-place removal uses
queue.splice(0, head) which is O(n) and can degrade performance for
large/high-throughput queues; replace this with a head index strategy: introduce
a numeric headIndex (initially 0) and increment headIndex by head instead of
calling splice, update all code that reads the queue to account for headIndex
(e.g., treat logical item i as queue[headIndex + i] or shift iteration start to
headIndex), and add a periodic rebase when headIndex exceeds a threshold (e.g.,
> 1024 or > queue.length/2) to compact the underlying array by performing one
splice/slice to reset headIndex to 0; locate uses by searching for the
variables/expressions head, queue, and queue.splice in this module and update
them consistently.
docs/package.json (1)

8-8: Cross-platform compatibility note for cf-typegen script.

The mv command is Unix-specific. If Windows developers without WSL need to run this script, consider using a cross-platform alternative like shx mv or a Node.js-based move utility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/package.json` at line 8, The "cf-typegen" npm script uses the Unix-only
"mv" command; make it cross-platform by replacing the mv call in the
"cf-typegen" script (the "cf-typegen" entry in package.json) with a
cross-platform mover such as "shx mv" or a small Node-based move script; if you
choose "shx", add "shx" as a devDependency and update the script to use "shx mv
worker-configuration.d.ts src/" so Windows users without WSL can run it, or
alternatively implement a Node script (e.g., move-types.js) and call it from the
"cf-typegen" script.
docs/src/worker-configuration.d.ts (1)

1-3: Stop reintroducing eslint-disable in generated typings.

This regeneration still carries /* eslint-disable */, so typegen will keep fighting the repo lint policy unless the generation step rewrites those markers or this artifact is excluded from that rule.

As per coding guidelines, "**/*.{ts,tsx,js,jsx}: Use trunk-ignore comments to suppress lint warnings, not eslint-disable."

Also applies to: 34-34

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/worker-configuration.d.ts` around lines 1 - 3, The generated typings
include the literal "/* eslint-disable */" which reintroduces eslint
suppression; remove that token and either replace it with the
repository-approved trunk-ignore comment (e.g. add a
trunk-ignore-file/trunk-ignore(eslint) comment at the top per repo guidelines)
or update the type generation step (Wrangler/typegen) to not emit eslint-disable
so regenerated files use trunk-ignore instead; target the generated header that
contains "/* eslint-disable */" to implement the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.trunk/trunk.yaml:
- Around line 26-28: Remove the blanket suppression of the osv-scanner for
pnpm-lock.yaml in the trunk.yaml (the "linters: [osv-scanner]" exclusion for
'**/pnpm-lock.yaml') and instead add per-lockfile exemption files: create an
osv-scanner.toml alongside each pnpm-lock.yaml that requires exceptions,
populate it with [[IgnoredVulns]] entries listing specific CVE/GHSA IDs and an
explicit rationale for each exemption; keep no global/blanket ignores in
trunk.yaml and ensure trunk.yaml only references linters normally so the scanner
covers pnpm-lock.yaml unless a specific osv-scanner.toml exists.

In `@docs/src/routes/docs/examples/api-caching/`+page.svx:
- Line 11: The seo.description override (seo.description) is 164 characters and
must be trimmed to 160 characters or fewer to match the fallback; update the
string value assigned to seo.description in the +page.svx content to a shorter
phrasing (remove redundant words like "expiration" → "expiry" or shorten
clauses) so the full description length is ≤160 while preserving meaning and
references to `@humanspeak/memory-cache` and TTL-based caching.

In `@docs/src/routes/docs/examples/async-fetching/`+page.svx:
- Line 11: The seo.description value (seo.description) exceeds the 160-character
SEO cap — shorten it to <=160 chars while preserving key phrases like
"getOrSet", "thundering herd prevention", "request deduplication", and "error
handling" (and mention "@humanspeak/memory-cache" if possible); update the
string assigned to seo.description in the +page.svx file to a more concise
sentence that conveys the same intent and keywords.

In `@docs/src/routes/docs/examples/computed-values/`+page.svx:
- Line 11: The seo.description string assigned to seo.description is 176
characters and must be shortened to <=160 chars; edit the value of
seo.description (the string literal on line assigning seo.description) to a
concise version under 160 characters that still conveys caching expensive
computations, performance tracking, and hooks monitoring with
`@humanspeak/memory-cache`, then verify the new string length is <=160.

In `@docs/src/routes/docs/examples/configuration/`+page.svx:
- Line 11: The meta description assigned to seo.description is 161 characters
and must be shortened to 160 or fewer characters; edit the string value in the
seo.description assignment (the line containing "seo.description = '...'" in the
+page.svx example) to a concise version under or equal to 160 characters—remove
or rephrase nonessential words (e.g., shorten phrases like "that rarely changes"
or "with `@humanspeak/memory-cache`") and verify the final string length is <=160
before committing.

In `@docs/src/routes/docs/examples/database-caching/`+page.svx:
- Line 11: Trim the seo.description string (the seo.description assignment) to
160 characters or fewer; keep the core messaging by preserving key phrases such
as "Cache expensive database queries", "@cached decorator", and a short mention
of "@humanspeak/memory-cache" and "TTL" or "query monitoring", and replace the
current long sentence with a concise version that fits the 160-char SEO limit.

In `@docs/src/routes/docs/examples/monitoring/`+page.svx:
- Line 11: The seo.description string assignment is too long and should be
trimmed to ~150–160 characters to avoid snippet truncation; edit the
seo.description value (the seo.description assignment) to a concise summary that
keeps key terms like "@humanspeak/memory-cache", "DataDog", "Prometheus", and
"observability" while removing extra phrasing — aim for a single short sentence
mentioning integration with DataDog/Prometheus and using hooks to monitor hit
rates/evictions/cache health.

In `@docs/src/routes/docs/examples/multi-tenant/`+page.svx:
- Line 11: The SEO description assigned to seo.description currently exceeds the
160-character limit (161 chars); update the string value of seo.description (the
description assignment shown) to be at most 160 characters by trimming or
rephrasing—e.g., remove/shorten a word or punctuation while preserving meaning
about prefix/wildcard deletion, hierarchical keys, and
`@humanspeak/memory-cache`—so the resulting string length is ≤160.

In `@docs/src/routes/docs/examples/rate-limiting/`+page.svx:
- Line 11: The meta description in the seo.description assignment is 175
characters and exceeds the 160-char target; update the seo.description string to
a concise version (<=160 chars) that preserves the core meaning (rate limiting
with `@humanspeak/memory-cache`, Express middleware, configurable thresholds, and
monitoring) so it won't be truncated.

In `@docs/src/routes/docs/examples/service-class/`+page.svx:
- Line 11: The meta description assigned to seo.description is 174 characters
and exceeds the 160-char target; update the string in the seo.description
assignment to be <=160 characters by shortening wording while retaining key
terms (e.g., "service class", "@cached", "memoization",
"@humanspeak/memory-cache") so the description remains informative but under the
limit.

In `@docs/src/routes/docs/examples/sessions/`+page.svx:
- Line 11: The SEO meta description in the docs page is over 160 characters;
shorten the string assigned to seo.description in +page.svx to ≤160 characters
while preserving the key message (session storage with automatic TTL and audit
logging, lightweight TypeScript/Node in-memory store). Edit the seo.description
assignment to a concise sentence that mentions: sessions, automatic TTL
expiration, audit logging, and `@humanspeak/memory-cache` (or just “in-memory
session store”) and verify the final string length is ≤160 characters.

In `@docs/src/routes/docs/getting-started/`+page.svx:
- Line 112: Update the hooks documentation entry to list the actual supported
lifecycle hooks: replace the current hook list (`onEvict`, `onExpire`, `onSet`,
`onDelete`, `onClear`) with the correct set: `onHit`, `onMiss`, `onSet`,
`onEvict`, `onExpire`, `onDelete`; remove the non-existent `onClear` and add
`onHit` and `onMiss` so the docs match the API type definition and event names
used by the implementation.

In `@docs/src/worker-configuration.d.ts`:
- Around line 10716-10736: The docs examples misrepresent the Stream API:
methods like videos.upload and videos.createDirectUpload are on the
StreamBinding itself (StreamBinding.videos.*) not under a per-video object, and
several example calls are missing await for promise-returning methods. Update
the examples to call StreamBinding-level methods directly (e.g.,
env.STREAM.videos.upload / env.STREAM.videos.createDirectUpload) and ensure all
promise-returning calls use await (for example await
env.STREAM.video(id).downloads.generate(), await video.captions.list(), await
video.details()), keeping the same wording but correcting the call targets and
adding await.

In `@src/cache.statistics.test.ts`:
- Around line 221-237: The test currently never triggers compaction because
MemoryCache.set() coalesces consecutive tail entries for the same key; modify
the test loop in the 'should compact expiration queue when tombstones
accumulate' case to break tail coalescing by interleaving writes (e.g.,
alternate setting 'key' and a different key like 'other') so the internal queue
grows (~20 entries) while cache.size() remains 1, then call ttlCache.prune() and
assert that compaction actually ran (expect pruned to be > 0 or the queue was
reduced), keep the microtask flush and verify ttlCache.size() === 1 and
ttlCache.get('key') === 'value9' to preserve existing semantics; locate changes
around MemoryCache.set(), prune(), and the test name to update the loop and
assertions.

---

Outside diff comments:
In `@docs/src/worker-configuration.d.ts`:
- Around line 11487-11494: Add a JSDoc comment for the html.cssSelector option
on the ConversionOptions type so the generated docs explain what the selector
scopes and how it behaves; locate the ConversionOptions declaration (the html
property under ConversionOptions and the nested images options where
convertOGImage is defined) and add a short JSDoc describing that cssSelector
accepts a CSS selector string used to scope which elements or parts of the HTML
are converted (include examples like "body" or ".article-content"), note whether
it accepts multiple selectors, and mention any sanitize/host/hostname
interactions or selector precedence so the docs generator will surface this
explanation.

---

Nitpick comments:
In `@docs/package.json`:
- Line 8: The "cf-typegen" npm script uses the Unix-only "mv" command; make it
cross-platform by replacing the mv call in the "cf-typegen" script (the
"cf-typegen" entry in package.json) with a cross-platform mover such as "shx mv"
or a small Node-based move script; if you choose "shx", add "shx" as a
devDependency and update the script to use "shx mv worker-configuration.d.ts
src/" so Windows users without WSL can run it, or alternatively implement a Node
script (e.g., move-types.js) and call it from the "cf-typegen" script.

In `@docs/src/worker-configuration.d.ts`:
- Around line 1-3: The generated typings include the literal "/* eslint-disable
*/" which reintroduces eslint suppression; remove that token and either replace
it with the repository-approved trunk-ignore comment (e.g. add a
trunk-ignore-file/trunk-ignore(eslint) comment at the top per repo guidelines)
or update the type generation step (Wrangler/typegen) to not emit eslint-disable
so regenerated files use trunk-ignore instead; target the generated header that
contains "/* eslint-disable */" to implement the change.

In `@src/cache.ts`:
- Around line 889-892: The current in-place removal uses queue.splice(0, head)
which is O(n) and can degrade performance for large/high-throughput queues;
replace this with a head index strategy: introduce a numeric headIndex
(initially 0) and increment headIndex by head instead of calling splice, update
all code that reads the queue to account for headIndex (e.g., treat logical item
i as queue[headIndex + i] or shift iteration start to headIndex), and add a
periodic rebase when headIndex exceeds a threshold (e.g., > 1024 or >
queue.length/2) to compact the underlying array by performing one splice/slice
to reset headIndex to 0; locate uses by searching for the variables/expressions
head, queue, and queue.splice in this module and update them consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5e01ef8c-9679-4b47-99ce-87e81dfd472d

📥 Commits

Reviewing files that changed from the base of the PR and between 950916d and 0d8b5eb.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (40)
  • .github/workflows/npm-publish.yml
  • .github/workflows/run-tests.yml
  • .trunk/trunk.yaml
  • docs/package.json
  • docs/src/lib/sitemap-manifest.json
  • docs/src/routes/docs/api/cached-decorator/+page.svx
  • docs/src/routes/docs/api/cached-decorator/+page.ts
  • docs/src/routes/docs/api/memory-cache/+page.ts
  • docs/src/routes/docs/examples/+page.ts
  • docs/src/routes/docs/examples/api-caching/+page.svx
  • docs/src/routes/docs/examples/api-caching/+page.ts
  • docs/src/routes/docs/examples/async-fetching/+page.svx
  • docs/src/routes/docs/examples/async-fetching/+page.ts
  • docs/src/routes/docs/examples/computed-values/+page.svx
  • docs/src/routes/docs/examples/computed-values/+page.ts
  • docs/src/routes/docs/examples/configuration/+page.svx
  • docs/src/routes/docs/examples/configuration/+page.ts
  • docs/src/routes/docs/examples/database-caching/+page.svx
  • docs/src/routes/docs/examples/database-caching/+page.ts
  • docs/src/routes/docs/examples/monitoring/+page.svx
  • docs/src/routes/docs/examples/monitoring/+page.ts
  • docs/src/routes/docs/examples/multi-tenant/+page.svx
  • docs/src/routes/docs/examples/multi-tenant/+page.ts
  • docs/src/routes/docs/examples/rate-limiting/+page.svx
  • docs/src/routes/docs/examples/rate-limiting/+page.ts
  • docs/src/routes/docs/examples/service-class/+page.svx
  • docs/src/routes/docs/examples/service-class/+page.ts
  • docs/src/routes/docs/examples/sessions/+page.svx
  • docs/src/routes/docs/examples/sessions/+page.ts
  • docs/src/routes/docs/getting-started/+page.svx
  • docs/src/routes/docs/getting-started/+page.ts
  • docs/src/routes/examples/basic-cache/+page.ts
  • docs/src/routes/examples/cache-statistics/+page.ts
  • docs/src/routes/examples/lru-eviction/+page.ts
  • docs/src/routes/examples/ttl-expiration/+page.ts
  • docs/src/worker-configuration.d.ts
  • package.json
  • src/cache.lru.test.ts
  • src/cache.statistics.test.ts
  • src/cache.ts
💤 Files with no reviewable changes (1)
  • src/cache.lru.test.ts

Comment thread .trunk/trunk.yaml
Comment on lines +26 to +28
- linters: [osv-scanner]
paths:
- '**/pnpm-lock.yaml'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect current Trunk/OSV suppression scope
rg -n -C3 'osv-scanner|pnpm-lock.yaml|ignore' .trunk/trunk.yaml

# Look for any existing OSV-specific policy files and advisory-level suppressions
fd -HI 'osv*'
rg -n -C2 'CVE-|GHSA-|ignore' || true

Repository: humanspeak/memory-cache

Length of output: 19942


🌐 Web query:

Trunk.io osv-scanner advisory CVE GHSA ignore ignore-advisories configuration

💡 Result:

How Trunk’s osv-scanner “ignore advisories” works (CVE / GHSA)

Trunk doesn’t have a separate ignore-advisories key for osv-scanner. Trunk runs Google’s osv-scanner on each lockfile and (by default) relies on osv-scanner’s own config file: osv-scanner.toml. Trunk’s plugin definition also declares osv-scanner.toml as the tool’s direct config. [1]

1) Ignore specific advisories (by CVE or GHSA)

Create osv-scanner.toml in the same directory as the lockfile you’re scanning, and add ignored vulnerability IDs under [[IgnoredVulns]]. [2]

[[IgnoredVulns]]
id = "CVE-2024-12345"
reason = "Not reachable in our build"

[[IgnoredVulns]]
id = "GHSA-xxxx-xxxx-xxxx"
reason = "False positive for our usage"

Notes:

  • osv-scanner.toml applies only to scanned files in that same directory (it does not automatically apply to child directories). [2]
  • Ignoring an ID also ignores its aliases (so ignoring a CVE typically ignores the corresponding GHSA/RustSec/etc, and vice-versa). [2]
  • osv-scanner output explicitly recommends this approach and shows the same [[IgnoredVulns]] format. [3]

2) (Optional) Use one global ignore file for the whole repo

If you want one ignore file to apply everywhere, osv-scanner supports --config=/path/to/config.toml. [2]
Trunk’s bundled command is essentially:

  • osv-scanner --lockfile=${target} --format json [1]

So, to use --config, you’d override the linter command in .trunk/trunk.yaml to add that flag (keeping the rest of the command structure the same). [1][2]


Sources
[1] Trunk plugins repo – osv-scanner linter definition (direct_configs: [osv-scanner.toml], run command) (github.com)
[2] OSV-Scanner documentation – configuration + [[IgnoredVulns]] + --config behavior (google.github.io)
[3] OSV-Scanner documentation – output guidance showing how to ignore a vulnerability via osv-scanner.toml (google.github.io)

Citations:


Remove blanket osv-scanner suppression for pnpm-lock.yaml.

Excluding the lockfile removes coverage for dependency vulnerabilities. Instead, create an osv-scanner.toml file at the lockfile location(s) with specific CVE/GHSA IDs under [[IgnoredVulns]] and include rationale for each exemption.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.trunk/trunk.yaml around lines 26 - 28, Remove the blanket suppression of
the osv-scanner for pnpm-lock.yaml in the trunk.yaml (the "linters:
[osv-scanner]" exclusion for '**/pnpm-lock.yaml') and instead add per-lockfile
exemption files: create an osv-scanner.toml alongside each pnpm-lock.yaml that
requires exceptions, populate it with [[IgnoredVulns]] entries listing specific
CVE/GHSA IDs and an explicit rationale for each exemption; keep no
global/blanket ignores in trunk.yaml and ensure trunk.yaml only references
linters normally so the scanner covers pnpm-lock.yaml unless a specific
osv-scanner.toml exists.

if (seo) {
seo.title = 'API Response Caching - Memory Cache'
seo.description = 'Cache API responses to reduce network requests and improve response times with @humanspeak/memory-cache'
seo.description = 'Cache API responses to reduce network requests and improve response times. Learn TTL-based expiration and cache invalidation patterns with @humanspeak/memory-cache.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Trim the seo.description override too.

+page.ts is within the 160-character target, but this override is still 164 characters, so the page can still emit an overlong description. Aligning it with the fallback keeps the metadata consistent.

Suggested trim
-      seo.description = 'Cache API responses to reduce network requests and improve response times. Learn TTL-based expiration and cache invalidation patterns with `@humanspeak/memory-cache`.'
+      seo.description = 'Cache API responses to reduce network requests and improve response times. Learn TTL-based expiration and invalidation patterns in Memory Cache.'
As per coding guidelines, "Documentation site built with SvelteKit. Check for accuracy and clarity."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/routes/docs/examples/api-caching/`+page.svx at line 11, The
seo.description override (seo.description) is 164 characters and must be trimmed
to 160 characters or fewer to match the fallback; update the string value
assigned to seo.description in the +page.svx content to a shorter phrasing
(remove redundant words like "expiration" → "expiry" or shorten clauses) so the
full description length is ≤160 while preserving meaning and references to
`@humanspeak/memory-cache` and TTL-based caching.

if (seo) {
seo.title = 'Async Fetching - Memory Cache'
seo.description = 'Cache expensive async operations with getOrSet in @humanspeak/memory-cache for thundering herd prevention'
seo.description = 'Cache expensive async operations with getOrSet for thundering herd prevention and request deduplication. Includes error handling patterns using @humanspeak/memory-cache.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep this meta description within the 160-character target.

Line 11 appears longer than the PR’s SEO cap, so snippet truncation is likely. Consider shortening while keeping the same keywords.

Suggested edit
-      seo.description = 'Cache expensive async operations with getOrSet for thundering herd prevention and request deduplication. Includes error handling patterns using `@humanspeak/memory-cache`.'
+      seo.description = 'Cache async operations with getOrSet for request deduplication and thundering-herd prevention, with practical error-handling patterns.'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
seo.description = 'Cache expensive async operations with getOrSet for thundering herd prevention and request deduplication. Includes error handling patterns using @humanspeak/memory-cache.'
seo.description = 'Cache async operations with getOrSet for request deduplication and thundering-herd prevention, with practical error-handling patterns.'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/routes/docs/examples/async-fetching/`+page.svx at line 11, The
seo.description value (seo.description) exceeds the 160-character SEO cap —
shorten it to <=160 chars while preserving key phrases like "getOrSet",
"thundering herd prevention", "request deduplication", and "error handling" (and
mention "@humanspeak/memory-cache" if possible); update the string assigned to
seo.description in the +page.svx file to a more concise sentence that conveys
the same intent and keywords.

if (seo) {
seo.title = 'Computed Value Caching - Memory Cache'
seo.description = 'Cache expensive computations to avoid redundant processing with @humanspeak/memory-cache'
seo.description = 'Cache expensive computations to avoid redundant processing and speed up repeated calculations. Includes performance tracking and hooks monitoring with @humanspeak/memory-cache.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Meta description exceeds the 160-char SEO threshold.
Line 11 is 176 chars, so this does not meet the stated trimming goal.

Suggested fix (<=160 chars)
-      seo.description = 'Cache expensive computations to avoid redundant processing and speed up repeated calculations. Includes performance tracking and hooks monitoring with `@humanspeak/memory-cache`.'
+      seo.description = 'Cache expensive computations to avoid redundant processing and speed repeated calculations. Includes tracking and hooks with `@humanspeak/memory-cache`.'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
seo.description = 'Cache expensive computations to avoid redundant processing and speed up repeated calculations. Includes performance tracking and hooks monitoring with @humanspeak/memory-cache.'
seo.description = 'Cache expensive computations to avoid redundant processing and speed repeated calculations. Includes tracking and hooks with `@humanspeak/memory-cache`.'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/routes/docs/examples/computed-values/`+page.svx at line 11, The
seo.description string assigned to seo.description is 176 characters and must be
shortened to <=160 chars; edit the value of seo.description (the string literal
on line assigning seo.description) to a concise version under 160 characters
that still conveys caching expensive computations, performance tracking, and
hooks monitoring with `@humanspeak/memory-cache`, then verify the new string
length is <=160.

if (seo) {
seo.title = 'Configuration Cache - Memory Cache'
seo.description = 'Cache configuration that rarely changes for faster application startup with @humanspeak/memory-cache'
seo.description = 'Cache configuration that rarely changes for faster application startup. Covers force refresh, change detection, and TTL strategies with @humanspeak/memory-cache.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Meta description exceeds the stated 160-char SEO cap.
Line 11 is 161 chars, so it misses the PR target.

Suggested fix (<=160 chars)
-      seo.description = 'Cache configuration that rarely changes for faster application startup. Covers force refresh, change detection, and TTL strategies with `@humanspeak/memory-cache`.'
+      seo.description = 'Cache configuration that rarely changes for faster startup. Covers force refresh, change detection, and TTL strategies with `@humanspeak/memory-cache`.'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
seo.description = 'Cache configuration that rarely changes for faster application startup. Covers force refresh, change detection, and TTL strategies with @humanspeak/memory-cache.'
seo.description = 'Cache configuration that rarely changes for faster startup. Covers force refresh, change detection, and TTL strategies with `@humanspeak/memory-cache`.'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/routes/docs/examples/configuration/`+page.svx at line 11, The meta
description assigned to seo.description is 161 characters and must be shortened
to 160 or fewer characters; edit the string value in the seo.description
assignment (the line containing "seo.description = '...'" in the +page.svx
example) to a concise version under or equal to 160 characters—remove or
rephrase nonessential words (e.g., shorten phrases like "that rarely changes" or
"with `@humanspeak/memory-cache`") and verify the final string length is <=160
before committing.

if (seo) {
seo.title = 'Service Class Pattern - Memory Cache'
seo.description = 'Complete service class example using the @cached decorator with @humanspeak/memory-cache'
seo.description = 'Complete service class example using the @cached decorator for automatic method-level memoization. Covers multiple methods and hooks monitoring with @humanspeak/memory-cache.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Meta description is over the 160-char target.
Line 11 is 174 chars; this will likely truncate in snippets.

Suggested fix (<=160 chars)
-      seo.description = 'Complete service class example using the `@cached` decorator for automatic method-level memoization. Covers multiple methods and hooks monitoring with `@humanspeak/memory-cache`.'
+      seo.description = 'Complete service class example using `@cached` for method-level memoization. Covers multiple methods and hooks monitoring with `@humanspeak/memory-cache`.'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
seo.description = 'Complete service class example using the @cached decorator for automatic method-level memoization. Covers multiple methods and hooks monitoring with @humanspeak/memory-cache.'
seo.description = 'Complete service class example using `@cached` for method-level memoization. Covers multiple methods and hooks monitoring with `@humanspeak/memory-cache`.'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/routes/docs/examples/service-class/`+page.svx at line 11, The meta
description assigned to seo.description is 174 characters and exceeds the
160-char target; update the string in the seo.description assignment to be <=160
characters by shortening wording while retaining key terms (e.g., "service
class", "@cached", "memoization", "@humanspeak/memory-cache") so the description
remains informative but under the limit.

if (seo) {
seo.title = 'Session Storage - Memory Cache'
seo.description = 'Store user sessions with automatic expiration using TTL in @humanspeak/memory-cache'
seo.description = 'Store user sessions with automatic TTL expiration and audit logging. A lightweight in-memory session store for TypeScript and Node.js using @humanspeak/memory-cache.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Trim SEO description to ≤160 chars

Line 11 appears longer than the PR’s 160-character target for meta descriptions, so this likely misses the SEO objective.

Proposed fix
-      seo.description = 'Store user sessions with automatic TTL expiration and audit logging. A lightweight in-memory session store for TypeScript and Node.js using `@humanspeak/memory-cache`.'
+      seo.description = 'Store user sessions with automatic TTL expiration and audit logging using `@humanspeak/memory-cache`, a lightweight in-memory session store for TypeScript.'

As per coding guidelines, docs/**: Documentation site built with SvelteKit. Check for accuracy and clarity.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
seo.description = 'Store user sessions with automatic TTL expiration and audit logging. A lightweight in-memory session store for TypeScript and Node.js using @humanspeak/memory-cache.'
seo.description = 'Store user sessions with automatic TTL expiration and audit logging using `@humanspeak/memory-cache`, a lightweight in-memory session store for TypeScript.'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/routes/docs/examples/sessions/`+page.svx at line 11, The SEO meta
description in the docs page is over 160 characters; shorten the string assigned
to seo.description in +page.svx to ≤160 characters while preserving the key
message (session storage with automatic TTL and audit logging, lightweight
TypeScript/Node in-memory store). Edit the seo.description assignment to a
concise sentence that mentions: sessions, automatic TTL expiration, audit
logging, and `@humanspeak/memory-cache` (or just “in-memory session store”) and
verify the final string length is ≤160 characters.

|--------|------|---------|-------------|
| `maxSize` | `number` | `100` | Maximum number of entries before eviction. Set to `0` for unlimited. |
| `ttl` | `number` | `300000` | Time-to-live in milliseconds. Set to `0` for no expiration. |
| `hooks` | `object` | — | Lifecycle hooks (`onEvict`, `onExpire`, `onSet`, `onDelete`, `onClear`) for reacting to cache events. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find hook names referenced across docs and source/types
rg -n -C2 '\bonHit\b|\bonMiss\b|\bonEvict\b|\bonExpire\b|\bonSet\b|\bonDelete\b|\bonClear\b|\bhooks\b'

# Locate memory-cache type/interface declarations for hooks
rg -n -C3 'interface .*Hook|type .*Hook|hooks\s*:' --type=ts

Repository: humanspeak/memory-cache

Length of output: 50381


Update the hooks list to include all supported hooks and remove the non-existent onClear.

Line 112 lists onEvict, onExpire, onSet, onDelete, onClear, but the actual supported hooks are onHit, onMiss, onSet, onEvict, onExpire, onDelete (see the complete type definition in the API reference). The current list is missing onHit and onMiss and incorrectly includes onClear.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/routes/docs/getting-started/`+page.svx at line 112, Update the hooks
documentation entry to list the actual supported lifecycle hooks: replace the
current hook list (`onEvict`, `onExpire`, `onSet`, `onDelete`, `onClear`) with
the correct set: `onHit`, `onMiss`, `onSet`, `onEvict`, `onExpire`, `onDelete`;
remove the non-existent `onClear` and add `onHit` and `onMiss` so the docs match
the API type definition and event names used by the implementation.

Comment on lines +10716 to +10736
/**
* Binding entrypoint for Cloudflare Stream.
*
* Usage:
* - Binding-level operations:
* `await env.STREAM.videos.upload`
* `await env.STREAM.videos.createDirectUpload`
* `await env.STREAM.videos.*`
* `await env.STREAM.watermarks.*`
* - Per-video operations:
* `await env.STREAM.video(id).downloads.*`
* `await env.STREAM.video(id).captions.*`
*
* Example usage:
* ```ts
* await env.STREAM.video(id).downloads.generate();
*
* const video = env.STREAM.video(id)
* const captions = video.captions.list();
* const videoDetails = video.details()
* ```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix the Stream examples to match the declared API.

Lines 10721-10724 point to env.STREAM.videos.upload / createDirectUpload, but those methods exist on StreamBinding itself. Lines 10734-10735 also omit await for promise-returning calls, so the generated docs are misleading.

Suggested doc fix
- *   `await env.STREAM.videos.upload`
- *   `await env.STREAM.videos.createDirectUpload`
+ *   `await env.STREAM.upload(file)`
+ *   `await env.STREAM.createDirectUpload(params)`
  *   `await env.STREAM.videos.*`
  *   `await env.STREAM.watermarks.*`
@@
- * const captions = video.captions.list();
- * const videoDetails = video.details()
+ * const captions = await video.captions.list();
+ * const videoDetails = await video.details();

As per coding guidelines, "docs/**: Documentation site built with SvelteKit. Check for accuracy and clarity." and "**/*.{ts,tsx}: Always use async/await for promises."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/worker-configuration.d.ts` around lines 10716 - 10736, The docs
examples misrepresent the Stream API: methods like videos.upload and
videos.createDirectUpload are on the StreamBinding itself
(StreamBinding.videos.*) not under a per-video object, and several example calls
are missing await for promise-returning methods. Update the examples to call
StreamBinding-level methods directly (e.g., env.STREAM.videos.upload /
env.STREAM.videos.createDirectUpload) and ensure all promise-returning calls use
await (for example await env.STREAM.video(id).downloads.generate(), await
video.captions.list(), await video.details()), keeping the same wording but
correcting the call targets and adding await.

Comment on lines +221 to +237
it('should compact expiration queue when tombstones accumulate', async () => {
const ttlCache = new MemoryCache<string>({ ttl: 100 })

// Overwrite the same key many times to create tombstones in the queue
// Each set() pushes a new queue entry; only the last timestamp is live
for (let i = 0; i < 10; i++) {
ttlCache.set('key', `value${i}`)
}

// Cache has 1 entry, queue has 10 entries (> 2 * 1) → compaction triggers
const pruned = ttlCache.prune()
expect(pruned).toBe(0)
// Flush microtask so background compaction runs
await new Promise<void>((resolve) => queueMicrotask(resolve))
expect(ttlCache.size()).toBe(1)
expect(ttlCache.get('key')).toBe('value9')
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Test does not exercise compaction due to queue coalescing.

The loop sets the same key 10 times consecutively. Due to the tail coalescing in set() (line 554 of cache.ts: if (tail?.key === key) { tail.timestamp = timestamp }), the queue only ever contains 1 entry, not 10.

Compaction triggers when queue.length > 2 * cache.size. With 1 queue entry and 1 cache entry, 1 > 2 is false — compaction never runs.

The test passes because the final assertions hold regardless, but the compaction code path remains untested.

🐛 Proposed fix to actually accumulate tombstones

Break coalescing by interleaving a different key:

-            // Overwrite the same key many times to create tombstones in the queue
-            // Each set() pushes a new queue entry; only the last timestamp is live
-            for (let i = 0; i < 10; i++) {
-                ttlCache.set('key', `value${i}`)
-            }
+            // Interleave keys to break tail coalescing and accumulate tombstones
+            for (let i = 0; i < 10; i++) {
+                ttlCache.set('key', `value${i}`)
+                ttlCache.set('other', 'x') // prevents next 'key' from coalescing
+            }
+            ttlCache.delete('other') // clean up helper key

After this, the queue will have ~20 entries (10 for 'key', 10 for 'other'), cache has 1 entry ('key'), and 20 > 2 * 1 triggers compaction.

Update assertion to match:

-            expect(ttlCache.get('key')).toBe('value9')
+            expect(ttlCache.get('key')).toBe('value9')
+            // Optionally verify queue was compacted by checking internal state or adding a second prune() call
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cache.statistics.test.ts` around lines 221 - 237, The test currently
never triggers compaction because MemoryCache.set() coalesces consecutive tail
entries for the same key; modify the test loop in the 'should compact expiration
queue when tombstones accumulate' case to break tail coalescing by interleaving
writes (e.g., alternate setting 'key' and a different key like 'other') so the
internal queue grows (~20 entries) while cache.size() remains 1, then call
ttlCache.prune() and assert that compaction actually ran (expect pruned to be >
0 or the queue was reduced), keep the microtask flush and verify ttlCache.size()
=== 1 and ttlCache.get('key') === 'value9' to preserve existing semantics;
locate changes around MemoryCache.set(), prune(), and the test name to update
the loop and assertions.

@jaysin586 jaysin586 closed this Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation skip-publish This is something important, but we dont want to publish it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant