fix: SEO improvements, CI hardening, and lint cleanup#131
Conversation
- 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>
📝 WalkthroughWalkthroughThis 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Important Merge conflicts detected (Beta)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 | 🟡 MinorDocument
cssSelectorbefore 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 avoidingsplicefor 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 aheadindex 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 forcf-typegenscript.The
mvcommand is Unix-specific. If Windows developers without WSL need to run this script, consider using a cross-platform alternative likeshx mvor 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 reintroducingeslint-disablein 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}: Usetrunk-ignorecomments to suppress lint warnings, noteslint-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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis 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.yamldocs/package.jsondocs/src/lib/sitemap-manifest.jsondocs/src/routes/docs/api/cached-decorator/+page.svxdocs/src/routes/docs/api/cached-decorator/+page.tsdocs/src/routes/docs/api/memory-cache/+page.tsdocs/src/routes/docs/examples/+page.tsdocs/src/routes/docs/examples/api-caching/+page.svxdocs/src/routes/docs/examples/api-caching/+page.tsdocs/src/routes/docs/examples/async-fetching/+page.svxdocs/src/routes/docs/examples/async-fetching/+page.tsdocs/src/routes/docs/examples/computed-values/+page.svxdocs/src/routes/docs/examples/computed-values/+page.tsdocs/src/routes/docs/examples/configuration/+page.svxdocs/src/routes/docs/examples/configuration/+page.tsdocs/src/routes/docs/examples/database-caching/+page.svxdocs/src/routes/docs/examples/database-caching/+page.tsdocs/src/routes/docs/examples/monitoring/+page.svxdocs/src/routes/docs/examples/monitoring/+page.tsdocs/src/routes/docs/examples/multi-tenant/+page.svxdocs/src/routes/docs/examples/multi-tenant/+page.tsdocs/src/routes/docs/examples/rate-limiting/+page.svxdocs/src/routes/docs/examples/rate-limiting/+page.tsdocs/src/routes/docs/examples/service-class/+page.svxdocs/src/routes/docs/examples/service-class/+page.tsdocs/src/routes/docs/examples/sessions/+page.svxdocs/src/routes/docs/examples/sessions/+page.tsdocs/src/routes/docs/getting-started/+page.svxdocs/src/routes/docs/getting-started/+page.tsdocs/src/routes/examples/basic-cache/+page.tsdocs/src/routes/examples/cache-statistics/+page.tsdocs/src/routes/examples/lru-eviction/+page.tsdocs/src/routes/examples/ttl-expiration/+page.tsdocs/src/worker-configuration.d.tspackage.jsonsrc/cache.lru.test.tssrc/cache.statistics.test.tssrc/cache.ts
💤 Files with no reviewable changes (1)
- src/cache.lru.test.ts
| - linters: [osv-scanner] | ||
| paths: | ||
| - '**/pnpm-lock.yaml' |
There was a problem hiding this comment.
🧩 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' || trueRepository: 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.tomlapplies 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-scanneroutput 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:
- 1: https://github.com/trunk-io/plugins/blob/main/linters/osv-scanner/plugin.yaml
- 2: https://google.github.io/osv-scanner/configuration/
- 3: https://google.github.io/osv-scanner/output/
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.' |
There was a problem hiding this comment.
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.'🤖 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.' |
There was a problem hiding this comment.
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.
| 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.' |
There was a problem hiding this comment.
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.
| 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.' |
There was a problem hiding this comment.
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.
| 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.' |
There was a problem hiding this comment.
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.
| 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.' |
There was a problem hiding this comment.
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.
| 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. | |
There was a problem hiding this comment.
🧩 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=tsRepository: 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.
| /** | ||
| * 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() | ||
| * ``` |
There was a problem hiding this comment.
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.
| 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') | ||
| }) |
There was a problem hiding this comment.
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 keyAfter 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.
Summary
ci/production) to resolve zizmorsecrets-outside-envwarningstrunk-ignore(eslint/@typescript-eslint/no-explicit-any)comments in LRU tests (rule not active in test files)osv-scannerignore forpnpm-lock.yamlto match other Humanspeak reposTest plan
environment:declarationstrunk checkto verify no remaining lint issues🤖 Generated with Claude Code