Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .changeset/deep-sort-sparse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cleverbrush/deep": patch
---

Reject sparse record arrays before sorting so missing elements cannot duplicate existing records or partially mutate input.
5 changes: 5 additions & 0 deletions .changeset/deep-traversal-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cleverbrush/deep": minor
---

Add sequential deepForEachAsync traversal and stable in-place deepSort with typed options, explicit validation and failure propagation.
8 changes: 8 additions & 0 deletions .changeset/react-form-blur-lifecycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@cleverbrush/react-form": minor
---

Add opt-in immediate blur validation that touches only the blurred field, and an
awaitable invalid-submission callback with existing duplicate and stale-result
protection. Opt-in validation-rule refresh retains edited values and field state
while adopting current bounds/messages and suppressing stale callbacks. Existing blur and submission defaults remain unchanged.
5 changes: 5 additions & 0 deletions .changeset/request-cancellation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cleverbrush/server": minor
---

Add withRequestSignal for cooperative request-disconnect, caller and deadline cancellation with deterministic lifecycle cleanup.
12 changes: 12 additions & 0 deletions .changeset/typed-paths-and-transaction-locks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@cleverbrush/server": minor
"@cleverbrush/client": patch
"@cleverbrush/orm": minor
"@cleverbrush/schema": patch
---

Add typed endpoint pathname construction and matching, shared with client URL generation and server routing. Route parameters are validated and encoded as individual components.

Add optional PostgreSQL advisory locks to ORM transactions, acquired before callbacks and released with their transaction.

Reject non-object inputs to open object schemas with inspectable validation errors, including nested arrays, instead of throwing descriptor errors.
9 changes: 6 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
node_modules
dist
*.tsbuildinfo
**/node_modules
**/dist
**/*.tsbuildinfo
/coverage
.git
**/.next
**/.turbo
/websites/docs/public/api-docs/latest
16 changes: 16 additions & 0 deletions .github/workflows/publish-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,34 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Check for unreleased changesets
id: changesets
run: |
node --input-type=module <<'NODE' >> "$GITHUB_OUTPUT"
import { readChangesets } from '@changesets/read';
const changesets = await readChangesets(process.cwd());
const publish = changesets.some(
changeset => changeset.releases.length > 0
);
process.stdout.write(`publish=${publish}\n`);
NODE

- name: Build
if: steps.changesets.outputs.publish == 'true'
run: npm run build

- name: Configure git user
if: steps.changesets.outputs.publish == 'true'
run: |
git config user.email "github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"

- name: Version packages as snapshot
if: steps.changesets.outputs.publish == 'true'
run: npx changeset version --snapshot beta

- name: Publish beta to npm
if: steps.changesets.outputs.publish == 'true'
run: npx changeset publish --tag beta --no-git-tag
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
26 changes: 23 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,23 @@ demo workflow.

Each package also has local source, tests, and exports under `libs/`.

Generate the API reference from the current package sources and READMEs:

```bash
npm run build
npm run docs
npm run docs:snapshot
```

Generation writes `websites/docs/public/api-docs/latest/` using the next version
planned by pending changesets, or the shared package version when none remain.
It leaves package versions, changelogs, and changesets untouched. The snapshot
command archives that output under `v<version>/` and updates the version picker.
It rejects stale output and existing snapshots. Commit the numbered archive;
`latest/` is generated during the docs container build and remains ignored by
Git. To generate and archive an explicit version, set `VERSION=1.2.3` for both
documentation commands.

## Quality Gates

Every change should leave these commands passing:
Expand All @@ -143,14 +160,17 @@ Published package behavior changes require a changeset.

## Release

This repository uses Changesets and fixed-version package releases.
This repository uses Changesets and fixed-version package releases. Add a
changeset with your package changes:

```bash
npm run changeset
npm run version
npm run release
```

After merging to `master`, the release workflow opens a version PR that runs
`npm run version`. Merging that PR runs `npm run release` to publish on npm.
Documentation generation does not require either command.

For beta releases:

```bash
Expand Down
15 changes: 8 additions & 7 deletions libs/async/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@
### Major Changes

- d916566: Make Framework query builders immutable and infer row schemas automatically.

Retain returned query builders, return synchronous builders from scopes and grouped predicates, and supply an explicit Framework object output schema for opaque raw SELECTs. Ordinary, aliased, polymorphic and ORM queries expose their row schemas directly. Projections replace scalar selections, and projected/aggregate/raw queries cannot perform entity writes. Reads and write-returning rows consistently preserve exact decimal/bigint strings, Date objects and SQL nulls.

All published Framework packages advance together to the next major version. Tracked entity objects remain mutable.

### Migrating from v4.x to v5

Remove `withRowSchema()` calls and retain each configured query instead of relying on mutation. Replace raw base-query overloads with explicit output contracts. See `libs/knex-schema/MIGRATION-v5.md` for the complete migration guide.

- c5b4dbc: Require Node.js 24+ consistently across all published packages. Correct the root and all published-package license files to BSD-3-Clause, matching package metadata and documentation, and verify license consistency in source and npm tarballs. See docs/MIGRATION-v5.md for migration guidance.

Harden JWT key/algorithm and claim validation, cookie parsing/serialization, and request-body lifecycle handling. Require explicit authorization scope for bounded server idempotency; coalesce concurrent retries and capture full response bodies. Bound response caching and bypass private, no-store and cookie-setting responses.

Preserve DI scope validation through factories and propagate registered optional-service failures. Fix batch response status/header capture, timeout abort-listener cleanup, concurrent deduplication response cloning, CLI database cleanup on validation/production-guard failures, and the missing client idempotency JavaScript export. Update security-sensitive dependencies and ensure OpenTelemetry disable flags override SDK defaults.

Add regression tests, package-consumer smoke checks, package-level unit coverage floors, migration/security documentation and release validation gates.

## 4.5.0
Expand Down
15 changes: 8 additions & 7 deletions libs/auth/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@
### Major Changes

- d916566: Make Framework query builders immutable and infer row schemas automatically.

Retain returned query builders, return synchronous builders from scopes and grouped predicates, and supply an explicit Framework object output schema for opaque raw SELECTs. Ordinary, aliased, polymorphic and ORM queries expose their row schemas directly. Projections replace scalar selections, and projected/aggregate/raw queries cannot perform entity writes. Reads and write-returning rows consistently preserve exact decimal/bigint strings, Date objects and SQL nulls.

All published Framework packages advance together to the next major version. Tracked entity objects remain mutable.

### Migrating from v4.x to v5

Remove `withRowSchema()` calls and retain each configured query instead of relying on mutation. Replace raw base-query overloads with explicit output contracts. See `libs/knex-schema/MIGRATION-v5.md` for the complete migration guide.

- c5b4dbc: Require Node.js 24+ consistently across all published packages. Correct the root and all published-package license files to BSD-3-Clause, matching package metadata and documentation, and verify license consistency in source and npm tarballs. See docs/MIGRATION-v5.md for migration guidance.

Harden JWT key/algorithm and claim validation, cookie parsing/serialization, and request-body lifecycle handling. Require explicit authorization scope for bounded server idempotency; coalesce concurrent retries and capture full response bodies. Bound response caching and bypass private, no-store and cookie-setting responses.

Preserve DI scope validation through factories and propagate registered optional-service failures. Fix batch response status/header capture, timeout abort-listener cleanup, concurrent deduplication response cloning, CLI database cleanup on validation/production-guard failures, and the missing client idempotency JavaScript export. Update security-sensitive dependencies and ensure OpenTelemetry disable flags override SDK defaults.

Add regression tests, package-consumer smoke checks, package-level unit coverage floors, migration/security documentation and release validation gates.

### Patch Changes
Expand Down
17 changes: 9 additions & 8 deletions libs/client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@
### Major Changes

- d916566: Make Framework query builders immutable and infer row schemas automatically.

Retain returned query builders, return synchronous builders from scopes and grouped predicates, and supply an explicit Framework object output schema for opaque raw SELECTs. Ordinary, aliased, polymorphic and ORM queries expose their row schemas directly. Projections replace scalar selections, and projected/aggregate/raw queries cannot perform entity writes. Reads and write-returning rows consistently preserve exact decimal/bigint strings, Date objects and SQL nulls.

All published Framework packages advance together to the next major version. Tracked entity objects remain mutable.

### Migrating from v4.x to v5

Remove `withRowSchema()` calls and retain each configured query instead of relying on mutation. Replace raw base-query overloads with explicit output contracts. See `libs/knex-schema/MIGRATION-v5.md` for the complete migration guide.

- c5b4dbc: Require Node.js 24+ consistently across all published packages. Correct the root and all published-package license files to BSD-3-Clause, matching package metadata and documentation, and verify license consistency in source and npm tarballs. See docs/MIGRATION-v5.md for migration guidance.

Harden JWT key/algorithm and claim validation, cookie parsing/serialization, and request-body lifecycle handling. Require explicit authorization scope for bounded server idempotency; coalesce concurrent retries and capture full response bodies. Bound response caching and bypass private, no-store and cookie-setting responses.

Preserve DI scope validation through factories and propagate registered optional-service failures. Fix batch response status/header capture, timeout abort-listener cleanup, concurrent deduplication response cloning, CLI database cleanup on validation/production-guard failures, and the missing client idempotency JavaScript export. Update security-sensitive dependencies and ensure OpenTelemetry disable flags override SDK defaults.

Add regression tests, package-consumer smoke checks, package-level unit coverage floors, migration/security documentation and release validation gates.

### Minor Changes
Expand All @@ -36,7 +37,7 @@
and part limits, reject truncated or duplicate singleton uploads, and support
file-only endpoints. Existing options-only uploads retain their single-file
shape and explicit MIME rejection reporting.

Add lossless JSONB object reads and writes using native object schemas with
`.acceptUnknownProps().jsonb()`. Preserve nested extension data through returning
rows and projections, validate JSON extensions in the database layer, align
Expand Down
8 changes: 8 additions & 0 deletions libs/client/src/path.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { string } from '@cleverbrush/schema';
import { route } from '@cleverbrush/server/contract';
import { describe, expect, test, vi } from 'vitest';
import { buildPath } from './path.js';

describe('buildPath', () => {
test('encodes real contract parameters without changing literal separators', () => {
const template = route({ id: string() })`/${p => p.id}/content`;
expect(buildPath('/files', template, { id: 'a/b%2F?#' })).toBe(
'/files/a%2Fb%252F%3F%23/content'
);
});
test('plain string template — appends to basePath', () => {
expect(buildPath('/api/todos', '')).toBe('/api/todos');
expect(buildPath('/api/todos', '/active')).toBe('/api/todos/active');
Expand Down
8 changes: 7 additions & 1 deletion libs/client/src/path.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { endpointPath } from '@cleverbrush/server/contract';
/**
* Builds the full request URL from endpoint metadata and optional path
* parameters.
Expand All @@ -24,7 +25,12 @@ export function buildPath(
}

if (typeof pathTemplate.serialize === 'function') {
return basePath + pathTemplate.serialize(params ?? {});
return typeof (pathTemplate as any).introspect === 'function'
? endpointPath(
{ introspect: () => ({ basePath, pathTemplate }) } as any,
params ?? {}
)
: basePath + pathTemplate.serialize(params ?? {});
}

return basePath;
Expand Down
15 changes: 8 additions & 7 deletions libs/deep/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@
### Major Changes

- d916566: Make Framework query builders immutable and infer row schemas automatically.

Retain returned query builders, return synchronous builders from scopes and grouped predicates, and supply an explicit Framework object output schema for opaque raw SELECTs. Ordinary, aliased, polymorphic and ORM queries expose their row schemas directly. Projections replace scalar selections, and projected/aggregate/raw queries cannot perform entity writes. Reads and write-returning rows consistently preserve exact decimal/bigint strings, Date objects and SQL nulls.

All published Framework packages advance together to the next major version. Tracked entity objects remain mutable.

### Migrating from v4.x to v5

Remove `withRowSchema()` calls and retain each configured query instead of relying on mutation. Replace raw base-query overloads with explicit output contracts. See `libs/knex-schema/MIGRATION-v5.md` for the complete migration guide.

- c5b4dbc: Require Node.js 24+ consistently across all published packages. Correct the root and all published-package license files to BSD-3-Clause, matching package metadata and documentation, and verify license consistency in source and npm tarballs. See docs/MIGRATION-v5.md for migration guidance.

Harden JWT key/algorithm and claim validation, cookie parsing/serialization, and request-body lifecycle handling. Require explicit authorization scope for bounded server idempotency; coalesce concurrent retries and capture full response bodies. Bound response caching and bypass private, no-store and cookie-setting responses.

Preserve DI scope validation through factories and propagate registered optional-service failures. Fix batch response status/header capture, timeout abort-listener cleanup, concurrent deduplication response cloning, CLI database cleanup on validation/production-guard failures, and the missing client idempotency JavaScript export. Update security-sensitive dependencies and ensure OpenTelemetry disable flags override SDK defaults.

Add regression tests, package-consumer smoke checks, package-level unit coverage floors, migration/security documentation and release validation gates.

### Patch Changes
Expand Down
43 changes: 43 additions & 0 deletions libs/deep/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,46 @@ const hash = HashObject({ name: 'John', age: 30 });
## License

BSD-3-Clause

### `deepForEachAsync(input, visitor, context?, options?)`

Visits plain records sequentially in parent-before-child order, awaiting each
visitor before continuing. Arrays, including nested arrays, are containers;
primitives, dates and custom instances are ignored. By default traversal follows
all own array-valued fields on a record. `options.optimizer` selects one such
field instead. Ordinary object-valued fields are not child containers.

```ts
import { deepForEachAsync } from '@cleverbrush/deep';

type Node = { name: string; children?: Node[] };
await deepForEachAsync<Node>(tree, async node => {
await saveNode(node.name);
}, undefined, { optimizer: 'children' });
```

`options.validation(node)` returning false skips that record and its subtree,
while later siblings are still visited. `context` is the visitor's `this` value.
Visitor/validation errors reject the returned promise immediately. Repeated
references are visited at each occurrence; a cycle on the active traversal path
rejects with `TypeError`. Traversal itself does not copy or mutate input; visitors
may mutate the records, and child arrays are read after their parent visitor.

### `deepSort(items, index, field)`

Stably sorts and returns the input array in place, using the numeric element at
`item[field][index]`. Equal keys preserve their original order and object identity.

```ts
import { deepSort } from '@cleverbrush/deep';

const nodes = [{ position: [0, 3] }, { position: [0, 1] }];
deepSort(nodes, 1, 'position');
// nodes is now [{ position: [0, 1] }, { position: [0, 3] }]
```

`index` must be a non-negative integer and exist in every selected field, or a
`RangeError` is thrown. Fields must be arrays containing finite numeric sort keys,
or a `TypeError` is thrown. All keys are checked before the array is changed.
Empty input is valid; path depth is independent of the number of records.
Sparse arrays and missing records are rejected before mutation.
Loading
Loading