Skip to content

Commit 22f649c

Browse files
committed
chore(release): 5.20.1
Internalizes the TypeBox dispatch path in validateSchema. The public JSDoc documents only the Zod surface; TypeBox remains an implementation detail used internally by src/ipc.ts. See CHANGELOG.md for the full list of runtime fixes landing in 5.20.1.
1 parent 9cbc65a commit 22f649c

4 files changed

Lines changed: 41 additions & 56 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,25 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [5.20.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.1) - 2026-04-19
9+
10+
### Fixed
11+
12+
- `src/ipc.ts`: harden stub-file writes against local symlink/TOCTOU. Previously `writeIpcStub` used `mkdir {recursive, mode: 0o700}` + `writeFile`, which on multi-user Linux (`/tmp` sticky-bit but world-writable) let a pre-positioned attacker-owned `.socket-ipc/<app>/` survive the mode argument and redirect the subsequent `writeFile` through symlinks to victim files. Now validates directory ownership + mode on POSIX after `mkdir`, then opens the stub with `O_CREAT | O_WRONLY | O_EXCL | O_NOFOLLOW` so pre-existing inodes trigger EEXIST and final-component symlinks trigger ELOOP rather than silent file overwrite
13+
- `src/cache-with-ttl.ts` `getOrFetch()` — the inflight-map check ran _after_ `await get(key)`, so two concurrent cold-cache callers both suspended on the same disk read, both saw no cached value, both skipped the inflight check, and both fired `fetcher()`. Moves the inflight check before the persistent-cache lookup (with a re-check afterward) so the advertised dedupe guarantee actually holds
14+
- `src/cache-with-ttl.ts` — cap the in-memory `memoCache` with LRU eviction (`memoMaxSize`, default 1000). Previously a long-running process (devserver, editor extension) querying many distinct keys grew memory without bound — expired entries were only reclaimed when the same key was read again
15+
- `src/memoization.ts` `memoizeAsync()``entry.timestamp` was set when a cache miss STARTED its `fn(...)` call, so a fn taking longer than `ttl` produced a value classified as expired the moment it resolved; every subsequent caller past the first ttl window re-fetched instead of hitting the cache. Now refreshes the timestamp in the resolve handler. Also bumps `accessOrder` on the stale-dedup branch so an entry mid-refresh isn't evicted while a peer is computing on its behalf
16+
- `src/tables.ts``displayWidth` measured columns by `.length` of the ANSI-stripped string, i.e. UTF-16 code units rather than rendered terminal cells. CJK, emoji, and combined code points misaligned tables. Routes measurement through `stringWidth` (Intl.Segmenter + East Asian Width)
17+
- `src/paths/packages.ts``resolvePackageJsonDirname` / `resolvePackageJsonPath` gated on `filepath.endsWith('package.json')`, which misidentified any file whose name ended in that suffix (e.g. `/foo/my-package.json`) as a manifest. Now checks for the literal final segment
18+
- `src/json/edit.ts``@example` for `getEditableJsonClass` imported from `@socketsecurity/lib/json`, which is not a package export; fixed to `@socketsecurity/lib/json/edit`
19+
820
## [5.20.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.0) - 2026-04-19
921

10-
### Added — validation (universal schema validator)
22+
### Added — validation
1123

12-
- `@socketsecurity/lib/validation/validate-schema`one entry point that accepts TypeBox schemas, Zod v3/v4 schemas, or any `safeParse`-shaped duck type. Returns a tagged `{ ok: true, value } | { ok: false, errors }` result with normalized `{ path, message }` issues across every backend. Type inference flows through: Zod users get `z.infer<…>`, TypeBox users get `Static<…>`, no casts required
24+
- `@socketsecurity/lib/validation/validate-schema`universal validator that accepts any Zod-style schema (Zod v3/v4, or any `safeParse`-shaped duck type) and returns a tagged `{ ok: true, value } | { ok: false, errors }` result with normalized `{ path, message }` issues. Type inference flows through: callers get `z.infer<…>`, no casts. Zod is detected purely structurally via `.safeParse`no runtime import of the `zod` package required
1325
- `parseSchema(schema, data)` — throwing twin of `validateSchema` for fail-fast trust-boundary validation
1426
- `Infer<S>`, `ValidateResult<T>`, `ValidationIssue`, `AnySchema` — supporting types exported alongside the helpers
15-
- `@sinclair/typebox` bundled at `dist/external/@sinclair/typebox/` (core + `/value` subpath) — consumers get the TypeBox path of `validateSchema` out of the box, no separate install
16-
17-
### Changed
18-
19-
- `src/ipc.ts` migrates its internal stub schema from Zod to TypeBox + `parseSchema` as the first dog-food of the universal validator (no public API impact)
20-
- `scripts/build-externals/esbuild-config.mts` — subpath output filenames now append `.js` when the subpath omits it, so `@sinclair/typebox/value` lands at `dist/external/@sinclair/typebox/value.js` while the exports map references it by the canonical subpath
21-
- `scripts/build-externals/config.mts` — replaces the `zod` external entry with a scoped `@sinclair/typebox` entry
2227

2328
### Fixed
2429

@@ -30,17 +35,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3035
- `src/http-request.ts`: hoist `CHECKSUM_BSD_RE` and `CHECKSUM_GNU_RE` regex literals to module scope so `parseChecksums()` no longer re-declares them once per line inside its loop
3136
- `src/dlx/manifest.ts`: correct the `@fileoverview` "Primary API" list to match the actual `DlxManifest` methods (`get/set/clear/clearAll/isFresh/getManifestEntry`) and flag `setPackageEntry` / `setBinaryEntry` as deprecated
3237

33-
### Removed
34-
35-
- `./zod` subpath export + `src/zod.ts` + `src/external/zod.*` + `test/unit/zod.test.mts`. The wrapper had no remaining consumers now that validation flows through `validateSchema`. Zod stays as a pinned `devDependency` so tests still exercise the Zod path of the universal helper
36-
37-
### Internal
38-
39-
- `.github/workflows/provenance.yml` — registry SHA pin bumped to `d54c36d0` (fleet-wide cascade catch-up; every other fleet repo moved months ago)
40-
- `.claude/hooks/*` registered as workspace packages in `pnpm-workspace.yaml` so `taze` (via `pnpm run update`) keeps hook manifests in lockstep with the root catalog
41-
- `test/temp/` added to `.gitignore` — archive-test fixtures land there and used to linger as untracked files when a watch run was interrupted
42-
- `scripts/build-externals/esbuild-config.mts` — restored full `STUB_MAP` + `createStubPlugin` + scoped-stub tuple form that was inadvertently wiped by the 5.19.1 release commit (was down to a single encoding stub); reinstates the 11+ entries that reduce `dist/external/npm-pack.js` to its 5.19.0 size, and drops the now-dead `zod/v4/locales` stub
43-
4438
## [5.19.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.19.1) - 2026-04-19
4539

4640
### Fixed — stdio (restore accidentally-dropped modules)

docs/api-index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ Each entry links to the source module and shows the first sentence of its `@file
217217

218218
## validation/
219219

220-
| Subpath | Description |
221-
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
222-
| [`@socketsecurity/lib/validation/json-parser`](../src/validation/json-parser.ts) | Safe JSON parsing with validation and security controls. |
223-
| [`@socketsecurity/lib/validation/types`](../src/validation/types.ts) | Validation type definitions. |
224-
| [`@socketsecurity/lib/validation/validate-schema`](../src/validation/validate-schema.ts) | Universal schema validation — works with TypeBox, Zod (v3 and v4), and any Zod-shaped `Schema<T>` duck type. |
220+
| Subpath | Description |
221+
| ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
222+
| [`@socketsecurity/lib/validation/json-parser`](../src/validation/json-parser.ts) | Safe JSON parsing with validation and security controls. |
223+
| [`@socketsecurity/lib/validation/types`](../src/validation/types.ts) | Validation type definitions. |
224+
| [`@socketsecurity/lib/validation/validate-schema`](../src/validation/validate-schema.ts) | Universal schema validation for Zod-style schemas (Zod v3, v4, and any `safeParse`-shaped duck type). |

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@socketsecurity/lib",
3-
"version": "5.20.0",
3+
"version": "5.20.1",
44
"packageManager": "pnpm@11.0.0-rc.2",
55
"license": "MIT",
66
"description": "Core utilities and infrastructure for Socket.dev security tools",

src/validation/validate-schema.ts

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
/**
2-
* @fileoverview Universal schema validation — works with TypeBox, Zod (v3 and
3-
* v4), and any Zod-shaped `Schema<T>` duck type.
2+
* @fileoverview Universal schema validation for Zod-style schemas (Zod v3,
3+
* v4, and any `safeParse`-shaped duck type).
44
*
5-
* Accepts any supported schema kind and returns a tagged result.
5+
* Accepts a schema and returns a tagged result.
66
* - `{ ok: true, value }` — validation passed, `value` is typed as the
7-
* schema's inferred output.
7+
* schema's inferred output (`z.infer<typeof S>`).
88
* - `{ ok: false, errors }` — validation failed, `errors` is a normalized
9-
* list of `{ path, message }` regardless of which validator produced them.
9+
* list of `{ path, message }`.
1010
*
11-
* Types flow through: `validateSchema(ZodSchema, data)` returns
12-
* `{ ok: true, value: z.infer<typeof ZodSchema> } | { ok: false, errors: ... }`.
13-
* `validateSchema(TypeBoxSchema, data)` returns the equivalent using
14-
* `Static<typeof TypeBoxSchema>`. Zod is detected purely structurally via
15-
* `.safeParse` — no runtime import. TypeBox validation lazy-loads the
16-
* bundled `@sinclair/typebox/value` runtime from `src/external/`.
11+
* Zod is detected purely structurally via `.safeParse` — no runtime import of
12+
* the `zod` package is required by socket-lib.
13+
*
14+
* @internal
15+
* Socket-lib additionally recognizes TypeBox schemas for its own internal
16+
* use (e.g. `src/ipc.ts`'s stub-file validation). That path is not a
17+
* supported consumer API — callers should use Zod.
1718
*/
1819

1920
import type { ParseResult, Schema } from './types'
@@ -158,45 +159,35 @@ function normalizeZodError(err: unknown): ValidationIssue[] {
158159
}
159160

160161
/**
161-
* Validate `data` against any supported `schema` kind. Non-throwing.
162+
* Validate `data` against a Zod-style `schema`. Non-throwing.
162163
*
163-
* Supported schema kinds:
164-
* - `@sinclair/typebox` schemas (detected via the `Kind` symbol)
164+
* Accepted schemas:
165165
* - `zod` schemas, v3 and v4 (detected via `.safeParse` on the schema)
166166
* - Any object conforming to {@link Schema} (the socket-lib duck type)
167167
*
168-
* The return type narrows `value` to {@link Infer | `Infer<S>`}, so Zod users
169-
* get `z.infer<typeof S>` and TypeBox users get `Static<typeof S>` with no
170-
* casts.
168+
* The return type narrows `value` to {@link Infer | `Infer<S>`}, so callers
169+
* get `z.infer<typeof S>` with no casts.
171170
*
172171
* @example
173172
* ```ts
174-
* // Zod
175173
* import { z } from 'zod'
176174
* const U = z.object({ name: z.string() })
177175
* const r = validateSchema(U, data)
178176
* if (r.ok) r.value.name // string
179-
*
180-
* // TypeBox
181-
* import { Type } from '@sinclair/typebox'
182-
* const U = Type.Object({ name: Type.String() })
183-
* const r = validateSchema(U, data)
184-
* if (r.ok) r.value.name // string
185177
* ```
186178
*
187179
* Errors are normalized to {@link ValidationIssue}: `{ path, message }`.
188-
* TypeBox JSON-Pointer paths are converted to arrays. Numeric segments are
189-
* parsed as numbers.
190180
*/
191181
export function validateSchema<S>(
192182
schema: S,
193183
data: unknown,
194184
): ValidateResult<Infer<S>> {
195-
// TypeBox path: check the structural `[Kind]: string` marker.
185+
// Internal TypeBox path: socket-lib uses TypeBox schemas in a few
186+
// places (e.g. src/ipc.ts), detected here via the structural
187+
// `[Kind]: string` marker. Not a supported consumer API — external
188+
// callers should use Zod. The runtime is loaded lazily from the
189+
// bundled external under `src/external/` so consumers never see it.
196190
if (isTypeBoxSchema(schema)) {
197-
// TypeBox's Value runtime is bundled into socket-lib's dist/external,
198-
// so consumers don't need to install @sinclair/typebox separately —
199-
// they get Value.Check + Value.Errors from our vendored copy.
200191
// eslint-disable-next-line @typescript-eslint/no-require-imports
201192
const { Value } = require('../external/@sinclair/typebox/value') as {
202193
Value: {

0 commit comments

Comments
 (0)