# Changelog

## [17.1.0] - 2026-05-21

### ✨ Features

### New `NotFoundError` and `NotSupportedError` exports

Two new error classes are exported from the package's `errors` barrel so adapters can signal narrow precondition failures by type instead of by message:

- `NotFoundError` — thrown by a `PhysicalStore` when an operation targets a missing entity (e.g. `update` called with an id that does not exist). Callers can branch on `instanceof NotFoundError` instead of parsing strings.
- `NotSupportedError` — thrown when an adapter cannot serve a given operation against its backing storage (e.g. `find` against a key/value store). Adapters throw at call time rather than at construction so the rest of the surface remains usable.

`InMemoryStore.update` now throws `NotFoundError` for the missing-entity case (was a plain `Error`); the message was tightened from `... cannot update!` to `... cannot update`. Sibling adapters (`@furystack/mongodb-store`, `@furystack/sequelize-store`, `@furystack/redis-store`) were updated in lockstep.

**Impact:** code that matched on the previous error message will keep working — `Error.message` still contains the entity id and the `cannot update` substring, only the trailing `!` was dropped. Callers can now switch to `instanceof NotFoundError`.

### 📚 Documentation

- Rewrote JSDoc across the public API (`defineStore`, `InMemoryStore`, `PhysicalStore`, the `errors/` family, `IdentityContext`, `globalDisposables`, `filterItems`, `User`) to follow the new value-test guidance: dropped restate-the-type narration, kept intent / trade-offs / constraints, and added type-only imports for cross-file `{@link}` targets.

### ⬆️ Dependencies

- Bump dev `vitest` to `^4.1.5`.
- Bumped `@types/node` to `^25.9.1` and `vitest` to `^4.1.7`. No source changes — dev-tooling bump only.

## [17.0.0] - 2026-04-25

### 💥 Breaking Changes

Stores are now first-class DI tokens. See the [v7 migration guide](../../docs/migrations/v7-functional-di.md) for rationale, recipes, and pitfalls.

- Removed `StoreManager`, `addStore(injector, store)`. Declare stores with `defineStore({ name, model, primaryKey, factory })` at module scope — the returned `StoreToken<T, PK>` is self-disposing on injector teardown and carries `model` + `primaryKey` metadata.
- Added `IdentityContext` as an interface + singleton token (previously a class). Bind a concrete implementation at app bootstrap; `useSystemIdentityContext` still returns a child injector with an elevated identity and is the recommended server-side elevation path.
- `Constructable` now lives in this package (moved from `@furystack/inject`). Any downstream package that used `Constructable` must switch its import.

### Quick reference

Before:

```ts
const sm = injector.getInstance(StoreManager)
sm.addStore(new InMemoryStore({ model: User, primaryKey: 'id' }))
const store = sm.getStoreFor(User, 'id')
```

After:

```ts
export const UserStore = defineStore({
  name: 'app/UserStore',
  model: User,
  primaryKey: 'id',
  factory: () => new InMemoryStore({ model: User, primaryKey: 'id' }),
})
const store = injector.get(UserStore)
```

## [16.0.4] - 2026-04-17

### ⬆️ Dependencies

- Raised `@types/node` to ^25.6.0, `typescript` to ^6.0.3, and `vitest` to ^4.1.4 so package development matches the workspace toolchain.

## [16.0.3] - 2026-03-27

### ⬆️ Dependencies

- Updated `vitest` to ^4.1.2

## [16.0.2] - 2026-03-25

### 📦 Build

- Removed deprecated `baseUrl` from tsconfig.json for TypeScript 6 compatibility

### ⬆️ Dependencies

- Upgraded `typescript` from ^5.9.3 to ^6.0.2
- Upgraded `vitest` from ^4.1.0 to ^4.1.1

## [16.0.1] - 2026-03-19

### ✨ Features

- Core package bump to 16.0.0 with the breaking change above and other internal refinements.

### 📚 Documentation

- Updated `IdentityContext` JSDoc to reflect the new explicit lifetime and parent‑chain inheritance.

### ⬆️ Dependencies

- Upgraded `vite` from ^7.3.1 to ^8.0.0 for improved build performance and new features
- Upgraded `vitest` from ^4.0.18 to ^4.1.0
- Upgraded `@vitest/coverage-istanbul` from ^4.0.18 to ^4.1.0

### 💥 Breaking Changes

### IdentityContext lifetime changed from `scoped` to `explicit`

`IdentityContext` now uses `@Injectable({ lifetime: 'explicit' })` so child injectors inherit the instance from their parent. Code that previously relied on the default scoped instance may now need to call `injector.setExplicitInstance` before accessing it. See migration notes in the package changelog.

## [16.0.0] - 2026-03-10

### 💥 Breaking Changes

### IdentityContext lifetime changed from `scoped` to `explicit`

`IdentityContext` now uses `@Injectable({ lifetime: 'explicit' })` instead of `@Injectable({ lifetime: 'scoped' })`.

**Why:** With `scoped` lifetime, child injectors created via `createChild()` could not inherit the `IdentityContext` from their parent. Each child silently created a new default instance whose methods returned `false` or threw `"No IdentityContext"`. This was a common source of confusion, especially in Shades frontend applications where nested component injectors should share the same identity.

With `explicit` lifetime, `getInstance(IdentityContext)` walks up the parent injector chain, so you only need to set it once on the root (or request-scoped) injector and all descendants will find it.

**Who is affected:** Code that called `injector.getInstance(IdentityContext)` without a prior `setExplicitInstance` call. Previously this returned a useless default instance; now it throws `CannotInstantiateExplicitLifetimeError`.

**Who is NOT affected:** All standard FuryStack server-side setups (`useHttpAuthentication`, `useJwtAuthentication`, `useSystemIdentityContext`, REST/WebSocket API managers) already call `setExplicitInstance` before accessing `IdentityContext` and will continue to work without changes.

**Migration:**

```typescript
// ❌ Before (scoped) — silently returned a broken default
const ctx = injector.getInstance(IdentityContext)

// ✅ After (explicit) — set it before accessing
injector.setExplicitInstance(myIdentityContext, IdentityContext)
const ctx = injector.getInstance(IdentityContext) // works

// ✅ Child injectors now inherit automatically
const child = injector.createChild()
const ctx = child.getInstance(IdentityContext) // same instance from parent
```

### 📚 Documentation

- Updated `IdentityContext` JSDoc to reflect the `explicit` lifetime, including setup instructions and parent inheritance behavior

## [15.2.5] - 2026-03-07

### ⬆️ Dependencies

- Updated `@types/node` from `^25.3.1` to `^25.3.5`

## [15.2.4] - 2026-03-06

### ⬆️ Dependencies

- Updated internal FuryStack dependencies

## [15.2.3] - 2026-03-03

### ⬆️ Dependencies

- Updated `@furystack/utils` with EventHub listener error handling and ObservableValue `onError` support

## [15.2.2] - 2026-02-26

### 🔧 Chores

- Normalized line endings in `store-manager.ts`

### ⬆️ Dependencies

- Bumped `@types/node` from ^25.3.0 to ^25.3.1

## [15.2.1] - 2026-02-26

### 📝 Documentation

- Added JSDoc recommendations to `PhysicalStore` and `StoreManager.getStoreFor()` pointing to `DataSet` as the preferred write gateway for application-level code

## [15.2.0] - 2026-02-22

### ✨ Features

### Public `filterItems()` function

Extracted the filter logic from `InMemoryStore` into a standalone `filterItems()` function, now exported from `@furystack/core`. This allows consumers to filter arrays using `FilterType` expressions without needing a store instance.

**Usage:**

```typescript
import { filterItems } from '@furystack/core'

const results = filterItems(myArray, {
  name: { $startsWith: 'foo' },
  age: { $gte: 18 },
})
```

### ♻️ Refactoring

- `InMemoryStore` now delegates to the public `filterItems()` function internally instead of using a private method

## [15.1.0] - 2026-02-19

### ✨ Features

### `SystemIdentityContext` -- elevated identity for trusted server-side operations

Added `SystemIdentityContext`, an `IdentityContext` subclass that is always authenticated and authorized. It is intended for background jobs, migrations, and seed scripts that need to write through the `DataSet` layer without an HTTP user session.

Also added the `useSystemIdentityContext()` helper that creates a scoped child injector with the elevated context. The returned injector is `AsyncDisposable` and works with `usingAsync()` for automatic cleanup.

**Usage:**

```typescript
import { useSystemIdentityContext } from '@furystack/core'
import { getDataSetFor } from '@furystack/repository'
import { usingAsync } from '@furystack/utils'

await usingAsync(useSystemIdentityContext({ injector, username: 'migration-job' }), async (systemInjector) => {
  const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
  await dataSet.add(systemInjector, newEntity)
})
```

### 📚 Documentation

- Expanded JSDoc on `PhysicalStore` to warn that writing directly to the store bypasses DataSet authorization, hooks, and events

### 🧪 Tests

- Added tests for `SystemIdentityContext` (authentication, authorization, custom username)
- Added tests for `useSystemIdentityContext` (child injector scoping, disposal, identity resolution)

### ⬆️ Dependencies

- Updated `@furystack/inject` and `@furystack/utils`

## [15.0.36] - 2026-02-11

### ⬆️ Dependencies

- Bump `vitest` from `^4.0.17` to `^4.0.18`
- Bump `@types/node` from `^25.0.10` to `^25.2.3`
- Updated internal dependencies

## [15.0.35] - 2026-02-09

### 🐛 Bug Fixes

- Fixed `getPort()` to assign deterministic port ranges per Vitest worker using `VITEST_POOL_ID` instead of a random base port, preventing port collisions in parallel test runs

### 🧪 Tests

- Refactored `globalDisposable` tests to use `usingAsync` for proper `Injector` disposal

## [15.0.34] - 2026-01-26

### 🔧 Chores

- Standardized author format, improved keywords, removed obsolete `gitHead`, added `engines` (Node 22+) and `sideEffects: false`

## [15.0.33] - 2026-01-26

### ⬆️ Dependencies

- Updated `@furystack/inject` with fix for singleton injector reference being overwritten by child injectors

## [15.0.32] - 2026-01-22

### ⬆️ Dependencies

- Dependency updates

### 📚 Documentation

- Improved README with clearer examples and better structure

### 🐛 Bug Fixes

- Fixed `getPort()` returning duplicate ports by reusing a shared generator instance instead of creating a new one on each call

### 🔧 Chores

- Migrated to centralized changelog management system
