Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .npmrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ ignore-scripts=true
link-workspace-packages=false
loglevel=error
prefer-workspace-packages=false
# Minimum release age - wait 7 days before installing newly published packages
# pnpm uses minimum-release-age (minutes), npm v11+ uses min-release-age (days)
minimum-release-age=10080
# Minimum release age for npm v11+ (days).
# pnpm equivalent is in pnpm-workspace.yaml (minimumReleaseAge).
min-release-age=7

trust-policy=no-downgrade
Expand Down
3 changes: 3 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
settings:
# Wait 7 days (10080 minutes) before installing newly published packages.
minimumReleaseAge: 10080
5 changes: 3 additions & 2 deletions scripts/update.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ async function main() {
process.stdout.write('\r\x1b[K')
}

// Always update Socket packages (bypass taze maturity period).
// Update Socket packages — bypass minimum-release-age since these are
// our own packages and we trust them immediately.
if (!quiet) {
logger.progress('Updating Socket packages...')
}
Expand All @@ -60,12 +61,12 @@ async function main() {
'-r',
],
{
env: { ...process.env, npm_config_minimum_release_age: '0' },
shell: WIN32,
stdio: quiet ? 'pipe' : 'inherit',
},
)

// Clear progress line.
if (!quiet) {
process.stdout.write('\r\x1b[K')
}
Expand Down
52 changes: 10 additions & 42 deletions test/unit/cache-with-ttl.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -467,52 +467,20 @@ describe.sequential('cache-with-ttl', () => {
await refreshCache.clear()
})

it('should treat far-future expiresAt as expired (clock skew protection)', async () => {
// This tests the fix in cache-with-ttl.ts:190-203
// The isExpired() function checks if expiresAt > now + ttl * 2
// to detect clock skew or corruption

const clockSkewCache = createTtlCache({
ttl: 1000, // 1 second TTL
prefix: 'clock-skew-test',
memoize: true, // Use memoization to test the isExpired logic directly
})

// Set a value - this will create an entry with normal expiration
await clockSkewCache.set('key', 'value')

// Verify value is cached
expect(await clockSkewCache.get<string>('key')).toBe('value')

// The internal isExpired function will reject entries where:
// expiresAt > Date.now() + ttl * 2
// This protects against clock skew where the system clock jumps forward

// Note: We can't easily test the actual clock skew scenario without
// manipulating cacache internals, but the fix is in place and handles:
// - Entries with far-future expiresAt (>2x TTL) are treated as expired
// - Normal future expiresAt values (within TTL) work correctly

await clockSkewCache.clear()
})

it('should handle slightly future expiresAt within reasonable bounds', async () => {
const normalCache = createTtlCache({
ttl: 5000, // 5 second TTL
prefix: 'normal-future-cache',
it('should expire entries and return undefined after TTL (memoized)', async () => {
const shortCache = createTtlCache({
ttl: 200,
prefix: 'short-memo-cache',
memoize: true,
})

// Set a value - expiresAt will be Date.now() + 5000
await normalCache.set('key', 'value')

// Value should be retrievable immediately (expiresAt is in future as expected)
const result = await normalCache.get<string>('key')
expect(result).toBe('value')
await shortCache.set('key', 'value')
expect(await shortCache.get<string>('key')).toBe('value')

// Only far-future values (>2x TTL) should be treated as expired
// This tests that normal future expiresAt values work correctly
await new Promise(resolve => setTimeout(resolve, 300))
expect(await shortCache.get<string>('key')).toBeUndefined()

await normalCache.clear()
await shortCache.clear()
})
})

Expand Down