diff --git a/.changeset/controller-set-array.md b/.changeset/controller-set-array.md deleted file mode 100644 index 9cdc9a779990..000000000000 --- a/.changeset/controller-set-array.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Fix `controller.set()` types for Array schemas - -`controller.set([Entity], rows)` and `controller.set(new schema.Array(Entity), rows)` now typecheck. This writes every row in one store update: each row merges with its stored entity, and entities not in `rows` stay. - -Rows are typed by the Entity's fields. The schema holds one Entity, [Union](https://dataclient.io/rest/api/Union) (for mixed types) or [Invalidate](https://dataclient.io/rest/api/Invalidate) (to delete), in an Array or [Values](https://dataclient.io/rest/api/Values) (which takes an object keyed by id). - -Batch `set()` needs `@data-client/rest` (or `endpoint`/`graphql`) from this release, since older Entity classes don't type as `EntityInterface`. - -```ts -// Before: TypeScript error on [Ticker], so batches became one set() per row -for (const row of rows) { - ctrl.set(Ticker, { product_id: row.product_id }, row); -} - -// After: one store update -ctrl.set([Ticker], rows); - -// Mixed Entity types, batch deletes, and rows keyed by id -const Message = new schema.Union({ ticker: Ticker, trade: Trade }, 'type'); -ctrl.set([Message], messages); -ctrl.set([new schema.Invalidate(Ticker)], [{ product_id: 'BTC-USD' }]); -ctrl.set(new schema.Values(Ticker), { 'BTC-USD': row }); -``` diff --git a/.changeset/controller-set-invalidate.md b/.changeset/controller-set-invalidate.md deleted file mode 100644 index 4760c39ecf33..000000000000 --- a/.changeset/controller-set-invalidate.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Fix `controller.set()` types for a single [Invalidate](https://dataclient.io/rest/api/Invalidate) - -Deleting one entity with `set()` worked at runtime but failed to typecheck, since `Invalidate` isn't -[Queryable](https://dataclient.io/rest/api/schema#queryable). Pass the schema and the row to delete; the row is typed -by the Entity's fields. - -```ts -// Before: TypeScript error, so a one-row batch was the workaround -ctrl.set([new Invalidate(Post)], [{ id: '5' }]); - -// After -ctrl.set(new Invalidate(Post), { id: '5' }); -``` - -Like batch `set()`, it takes no `args` and no updater function. diff --git a/.changeset/controller-set-value-types.md b/.changeset/controller-set-value-types.md deleted file mode 100644 index 7c01084d073a..000000000000 --- a/.changeset/controller-set-value-types.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Fix `controller.set()` accepting any value - -Values are now typed by the schema: Entities take their fields, while [Collection](https://dataclient.io/rest/api/Collection) -and [All](https://dataclient.io/rest/api/All) take a list of rows. [Query](https://dataclient.io/rest/api/Query) takes -the input of the schema it wraps, not what its `process()` returns. Updater functions must return the same. - -```ts -// Before: these all typechecked, then failed or wrote nothing at runtime -ctrl.set(new schema.All(Todo), 42); -ctrl.set(TodoResource.getList.schema, 'anything'); -ctrl.set(Todo, { id: '5' }, { id: '5', completed: 'yes' }); - -// After: TypeScript errors on the above; these typecheck -ctrl.set(TodoResource.getList.schema, [{ id: '5', completed: true }]); -ctrl.set(new schema.All(Todo), [{ id: '5', completed: true }]); -``` - -When each member declares its discriminator as a literal (like `readonly type = 'post'`), a -[Union](https://dataclient.io/rest/api/Union) row is checked against the member it selects. Only -declared fields are accepted, so a key read by a `schemaAttribute` function must be declared on each member. - -```ts -const Feed = new schema.Union({ post: Post, comment: Comment }, 'type'); -// TypeScript error: commentBody is a Comment field, not a Post field -ctrl.set(Feed, { id: '1', type: 'post' }, { type: 'post', commentBody: 'hi' }); -``` diff --git a/.changeset/controller-subclass-option.md b/.changeset/controller-subclass-option.md deleted file mode 100644 index dc29a3f7aac7..000000000000 --- a/.changeset/controller-subclass-option.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/react': patch -'@data-client/vue': patch -'@data-client/test': patch ---- - -Fix TypeScript error passing a `Controller` subclass to `DataProvider` or `DataClientPlugin` - -A plain `class MyController extends Controller` failed to typecheck as the `Controller` option of [DataProvider](https://dataclient.io/docs/api/DataProvider#Controller), Vue's [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin#Controller), and the `@data-client/react/redux` `DataProvider`, so the documented example needed a cast. `MockController()` from `@data-client/core/mock` had the same error when wrapping your subclass. These now typecheck, and you can drop the casts. - -```tsx -class MyController extends Controller { - doSomething = () => console.log('hi'); -} - -// Before: TypeScript error, so you had to cast - -app.use(DataClientPlugin, { Controller: MyController as typeof Controller }); - -// After - -app.use(DataClientPlugin, { Controller: MyController }); -``` diff --git a/.changeset/deleted-entity-undefined.md b/.changeset/deleted-entity-undefined.md deleted file mode 100644 index d3d19a19a87b..000000000000 --- a/.changeset/deleted-entity-undefined.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Fix `useCache()` and `useDLE()` returning a truthy `Symbol` for deleted entities - -After an entity was deleted and its refetch failed, `useCache()` and `useDLE()` (React and Vue) returned an internal -`Symbol` instead of `undefined`. Since a `Symbol` is truthy, "not loaded" checks passed, and code went on to use it as -the entity: - -```tsx -const todo = useCache(TodoResource.get, { id }); -if (!todo) return ; -// Before: reached here with a Symbol; todo.title was undefined and todo.title.trim() threw -// After: the placeholder renders -return ; -``` - -[Controller.getResponse()](https://dataclient.io/docs/api/Controller#getResponse) and -[Controller.fetchIfStale()](https://dataclient.io/docs/api/Controller#fetchIfStale) now also give `undefined` there, -like [Controller.get()](https://dataclient.io/docs/api/Controller#get) already did. diff --git a/.changeset/devtools-date-format-perf.md b/.changeset/devtools-date-format-perf.md deleted file mode 100644 index 056402c07d9b..000000000000 --- a/.changeset/devtools-date-format-perf.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Fix slow updates in development while Redux DevTools is open - -With the [Redux DevTools](https://dataclient.io/docs/getting-started/debugging) extension open, every store update -stalled the page while DevTools serialized the store: about 20ms with 50 entities, and 200ms with 500. Apps doing -many `controller.set()` calls, polling, or live updates would stutter in development. Each update now serializes -40-60x faster, and timestamps still show as readable times like `10:42:07.123 AM`. diff --git a/.changeset/drop-typescript-3.md b/.changeset/drop-typescript-3.md deleted file mode 100644 index c35770a331bd..000000000000 --- a/.changeset/drop-typescript-3.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@data-client/core': minor -'@data-client/endpoint': minor -'@data-client/normalizr': minor -'@data-client/react': minor -'@data-client/graphql': minor -'@data-client/img': minor -'@data-client/test': minor ---- - -BREAKING: Require TypeScript 4.0 or later - -The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and -`@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. - -```diff title="package.json" -- "typescript": "^3.9.0" -+ "typescript": "^4.0.0" -``` diff --git a/.changeset/entity-pk-readonly-args.md b/.changeset/entity-pk-readonly-args.md deleted file mode 100644 index 6cd0e9e187fc..000000000000 --- a/.changeset/entity-pk-readonly-args.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@data-client/endpoint': patch -'@data-client/rest': patch -'@data-client/graphql': patch ---- - -Fix Entity classes not assignable to `EntityInterface` - -[Entity.pk()](https://dataclient.io/rest/api/Entity#pk)'s static `args` parameter is now `readonly any[]`, matching `EntityInterface`. Entity classes can be passed where an `EntityInterface` is expected. - -```ts -import type { EntityInterface } from '@data-client/react'; - -// Before: TypeScript error (args is readonly in EntityInterface) -// After: typechecks -const schema: EntityInterface = User; -``` - -Overrides of `static pk()` that type `args` as a mutable array still compile, but a future breaking release will require `readonly any[]`, so update them now: - -```ts -class User extends Entity { - static pk(value: any, parent?: any, key?: string, args?: readonly any[]) { - return `${value.id}-${args?.[0]?.org}`; - } -} -``` diff --git a/.changeset/extend-process-params.md b/.changeset/extend-process-params.md deleted file mode 100644 index 29b6af3714db..000000000000 --- a/.changeset/extend-process-params.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@data-client/rest': patch ---- - -Type the `params` and `body` that `process()` receives in `RestEndpoint` options - -A `process(value, params)` method passed to `new RestEndpoint()`, `RestEndpoint.extend()` or `resource().extend()` used to get `params` typed as `any`, so a typo or a wrong assumption about a path parameter went unnoticed until runtime. They are now typed from the endpoint's `path`, `searchParams` and `body`, including a `path` set in the same `.extend()` call. - -```ts -const getUser = new RestEndpoint({ path: '/users/:id' }); - -const getUserById = getUser.extend({ - path: '/users/by-id/:userId', - process(value, params) { - params.userId; // string | number - params.id; // TypeScript error: 'id' is not a param of '/users/by-id/:userId' - return value; - }, -}); -``` - -Endpoints whose params are optional pass `params` as possibly `undefined`, so read it with `params?.page`. - -This can surface new TypeScript errors in existing `process()` methods that read a param the endpoint doesn't have, or that read optional `params` without a check. Each is a read that could be `undefined` or throw at runtime, so fix the param name or add the check. - -On TypeScript 5.x and earlier, `process(value, params)` in an `.extend()` that also sets `path` no longer fails with "implicitly has an 'any' type" under `strict`. diff --git a/.changeset/faster-rest-types.md b/.changeset/faster-rest-types.md deleted file mode 100644 index 48743f15d640..000000000000 --- a/.changeset/faster-rest-types.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@data-client/rest': patch -'@data-client/endpoint': patch -'@data-client/graphql': patch ---- - -Speed up TypeScript checking of `RestEndpoint`, `resource()` and `.extend()` - -Editors and `tsc` check code that defines or calls endpoints faster and with less memory. In our stress tests, a file of 150 RestEndpoints with long paths, `.extend()` and `.paginated()` checked in about half the time (3.1s → 1.6s) and memory (345MB → 207MB). Files that use `resource()` with React or Vue hooks did 22-25% less type work. TypeScript reports the same errors as before. - -On TypeScript 5.x and earlier, a `process(value, params)` method passed to `.extend()` no longer fails with "implicitly has an 'any' type" under `strict`, matching TypeScript 6+. TypeScript 4.0 also accepts a chained `.extend().extend()`. - -```ts -const getUser = new RestEndpoint({ path: '/users/:id', schema: User }); - -// Before (TypeScript 5.x and earlier): error TS7006: Parameter 'value' implicitly has an 'any' type. -// After: no error -const getUserName = getUser.extend({ - process(value, params) { - return value.name; - }, -}); -``` diff --git a/.changeset/fetch-meta-promise.md b/.changeset/fetch-meta-promise.md deleted file mode 100644 index a957d2e4b41d..000000000000 --- a/.changeset/fetch-meta-promise.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Type FETCH `action.meta.promise` as `Promise` - -Managers can now call `.finally()` and `.catch()` on a FETCH action's `meta.promise` without a TypeScript error. It was always a real `Promise` at runtime, but was typed `PromiseLike`, which only has `.then()`. - -```ts -// Before: TypeScript error on .finally(), so both callbacks went to .then() -const track = () => - trackTiming(action.endpoint.name, performance.now() - start); -action.meta.promise.then(track, track); - -// After -action.meta.promise - .finally(() => { - trackTiming(action.endpoint.name, performance.now() - start); - }) - // the fetch's caller handles errors; this only observes timing - .catch(() => {}); -``` diff --git a/.changeset/fixture-args-readonly.md b/.changeset/fixture-args-readonly.md deleted file mode 100644 index e95a5a622954..000000000000 --- a/.changeset/fixture-args-readonly.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/test': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Fixture `args` accept readonly tuples - -Fixtures written with `args: [...] as const` now type-check when passed to [MockResolver](https://dataclient.io/docs/api/MockResolver), `renderDataHook()`, Vue's `renderDataCompose()` or `mockInitialState()`. Before, TypeScript rejected them with "The type 'readonly [...]' is 'readonly' and cannot be assigned to the mutable type", so you had to drop `as const` or cast. - -```ts -const fixtures = [ - { - endpoint: TodoResource.getList, - args: [{ userId: 1 }] as const, - response: [{ id: 1, title: 'Write tests', userId: 1 }], - }, -]; - -// Before: type error on `fixtures`. After: works as written - - -; -``` diff --git a/.changeset/legacy-ts-endpoint-libcheck.md b/.changeset/legacy-ts-endpoint-libcheck.md deleted file mode 100644 index 6fde9e1a81a8..000000000000 --- a/.changeset/legacy-ts-endpoint-libcheck.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@data-client/endpoint': patch -'@data-client/rest': patch -'@data-client/graphql': patch ---- - -Fix more TypeScript 4.x errors when `skipLibCheck` is off - -[Entity](https://dataclient.io/rest/api/Entity), [Endpoint](https://dataclient.io/rest/api/Endpoint), [Union](https://dataclient.io/rest/api/Union) and [RestEndpoint](https://dataclient.io/rest/api/RestEndpoint) declarations no longer report errors on TypeScript 4.0 through 4.5. On TypeScript 4.0 and 4.1, an `Entity` can be an `Endpoint` schema again. - -```ts -import { Endpoint, Entity, schema } from '@data-client/endpoint'; - -class User extends Entity { - id = ''; - type = 'users'; -} -const getUser = new Endpoint( - (id: string) => fetch(`/users/${id}`).then(res => res.json()), - { schema: User }, -); -const feed = new schema.Union({ users: User }, 'type'); - -// Before (TypeScript 4.0, skipLibCheck: false): -// error TS2456: Type alias 'RemoveArray' circularly references itself. -// error TS2322: Type 'typeof User' is not assignable to type 'EntityInterface'. -// Before (TypeScript 4.2): -// error TS2344: Type 'TBase' does not satisfy the constraint 'new (...args: any) => any'. -// After: no errors -``` diff --git a/.changeset/legacy-ts-inline-type-imports.md b/.changeset/legacy-ts-inline-type-imports.md deleted file mode 100644 index 53d69390bc54..000000000000 --- a/.changeset/legacy-ts-inline-type-imports.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@data-client/react': patch -'@data-client/test': patch -'@data-client/vue': patch ---- - -Fix `',' expected` errors on TypeScript 4.0 through 4.4 - -Importing `@data-client/react/redux`, `@data-client/react/nextjs` or `@data-client/test` failed to compile on TypeScript before 4.5, even with `skipLibCheck` on, because their declaration files used syntax those versions can't parse. They now compile on TypeScript 4.0 and later. - -```ts -import { DataProvider } from '@data-client/react/nextjs'; -import { renderDataHook } from '@data-client/test'; - -// Before (TypeScript 4.0 to 4.4): -// node_modules/@data-client/react/lib/server/nextjs/DataProvider/DataProvider.d.ts(1,15): error TS1005: ',' expected. -// node_modules/@data-client/test/lib/makeRenderDataClient/index.d.ts(3,33): error TS1005: ',' expected. -// After: no errors -``` - -`@data-client/vue/test` types now also resolve with `moduleResolution: "node"`. diff --git a/.changeset/legacy-ts-noinfer.md b/.changeset/legacy-ts-noinfer.md deleted file mode 100644 index d27ac8b61936..000000000000 --- a/.changeset/legacy-ts-noinfer.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@data-client/endpoint': patch -'@data-client/normalizr': patch -'@data-client/rest': patch -'@data-client/graphql': patch -'@data-client/react': patch -'@data-client/vue': patch ---- - -Fix types for TypeScript 4.x when `skipLibCheck` is off - -TypeScript 4.0 through 4.7 no longer report `Cannot find name 'NoInfer'` from `@data-client/endpoint` or `@data-client/normalizr`, and TypeScript 4.0 through 4.9 no longer report `Only named exports may use 'export type'` from `@data-client/normalizr`. - -```ts -import { Entity } from '@data-client/endpoint'; -import { normalize } from '@data-client/normalizr'; - -// Before (TypeScript 4.7, skipLibCheck: false): -// error TS2304: Cannot find name 'NoInfer'. -// error TS1383: Only named exports may use 'export type'. -// After: no errors -``` diff --git a/.changeset/max-entity-depth-jsdoc.md b/.changeset/max-entity-depth-jsdoc.md deleted file mode 100644 index b02a3c7a6a7c..000000000000 --- a/.changeset/max-entity-depth-jsdoc.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@data-client/endpoint': patch -'@data-client/rest': patch -'@data-client/graphql': patch ---- - -Fix `Entity.maxEntityDepth` docs: the default is 64, not 128 - -Editor hover docs for `static maxEntityDepth` now show the real default. Runtime behavior is unchanged; set `maxEntityDepth` explicitly if you relied on 128. diff --git a/.changeset/prepare-store-redux-store.md b/.changeset/prepare-store-redux-store.md deleted file mode 100644 index 56a96c4c14fc..000000000000 --- a/.changeset/prepare-store-redux-store.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@data-client/react': patch ---- - -Fix TypeScript error passing `prepareStore()`'s store to react-redux's `` - -`prepareStore()` from `@data-client/react/redux` typed its `store` as a minimal object with only `getState()` and `subscribe()`, so [using it with React-Redux](https://dataclient.io/docs/guides/redux) needed a cast, and `store.dispatch()` was a TypeScript error. It's now typed as a Redux `Store`. Its `replaceReducer()` and `[Symbol.observable]()` aren't supported: they throw, and are typed as returning `never`. - -```tsx -const { store, selector, controller } = prepareStore( - initialState, - managers, - Controller, - otherReducers, - extraMiddlewares, -); - -// Before: TypeScript error, so you had to cast - - -// After - -``` diff --git a/.changeset/query-collection-push-body.md b/.changeset/query-collection-push-body.md deleted file mode 100644 index c5e9c39975b7..000000000000 --- a/.changeset/query-collection-push-body.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@data-client/rest': patch ---- - -Fix `RestEndpoint.push`, `unshift` and `remove` body types when a `Query` or `Lazy` wraps the endpoint's `Collection` - -Sorting or filtering a list with a [Query](https://dataclient.io/rest/api/Query) around its [Collection](https://dataclient.io/rest/api/Collection) made `getPosts.push` reject every body except `FormData`, though it adds to the list at runtime. The body is now typed from the Collection's Entity, so a correct body compiles and a wrong field is a TypeScript error. The same applies to a Collection wrapped in [Lazy](https://dataclient.io/rest/api/Lazy). - -```ts -const getPosts = new RestEndpoint({ - path: '/:group/posts', - searchParams: {} as { orderBy?: string }, - schema: new Query( - new Collection([Post], { nonFilterArgumentKeys: /orderBy/ }), - (posts, { orderBy } = {}) => sortBy(posts, orderBy), - ), -}); -``` - -If you cast the body to get past this error, the cast can go: - -```ts -// Before -ctrl.fetch(getPosts.push, { group: 'react' }, { title, author } as any); -// After -ctrl.fetch(getPosts.push, { group: 'react' }, { title, author }); -``` diff --git a/.changeset/render-data-hook-suspend-effects.md b/.changeset/render-data-hook-suspend-effects.md deleted file mode 100644 index 51fa328c9bff..000000000000 --- a/.changeset/render-data-hook-suspend-effects.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@data-client/test': patch ---- - -Fix mount effects when `renderDataHook()` suspends on the first render - -`renderDataHook()` and `makeRenderDataHook()` now run provider mount effects when the first render suspends, including `use(useFetch())`. The hook result stays unresolved until the data arrives. diff --git a/.changeset/resource-create-formdata.md b/.changeset/resource-create-formdata.md deleted file mode 100644 index a9f03cdffaba..000000000000 --- a/.changeset/resource-create-formdata.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@data-client/rest': patch ---- - -Fix TypeScript error passing `FormData` to `resource().create` - -`resource().create` sends a `FormData` body as-is, the same as `update`, `partialUpdate` and -`getList.push`, but its type only allowed an object, so submitting a form needed a cast. This now typechecks, -and you can drop the cast. `create` is deprecated, and its replacement `getList.push` takes `FormData` too. - -```tsx -
{ - e.preventDefault(); - // Before: TypeScript error, so you had to cast - ctrl.fetch(PostResource.create, new FormData(e.currentTarget) as any); - // After - ctrl.fetch(PostResource.create, new FormData(e.currentTarget)); - }} -> -``` diff --git a/.changeset/resource-extend-keeps-members.md b/.changeset/resource-extend-keeps-members.md deleted file mode 100644 index 159bcaf420b7..000000000000 --- a/.changeset/resource-extend-keeps-members.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@data-client/rest': patch ---- - -Fix `resource().extend({ get: ... })` dropping endpoints added earlier from its type - -Customizing a resource's standard endpoints with `.extend({ ... })` kept every endpoint at runtime, but TypeScript lost the ones added before it with `.extend('name', options)`, and the deprecated `create`. Using them was a type error even though they worked. - -```ts -const UserResource = resource({ path: '/users/:id', schema: User }) - .extend('current', { path: '/user' }) - .extend({ get: { dataExpiryLength: 60000 } }); - -// Before: Property 'current' does not exist -// After: no error -const me = await ctrl.fetch(UserResource.current); -``` diff --git a/.changeset/test-renderhook-ts4.md b/.changeset/test-renderhook-ts4.md deleted file mode 100644 index dfbe30431d2f..000000000000 --- a/.changeset/test-renderhook-ts4.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@data-client/test': patch ---- - -Fix `act` and `renderHook` typed as `any` on TypeScript 4.0–4.4 - -`act()`, `renderHook()` and `RenderHookOptions` from `@data-client/test` were `any` on TypeScript 4.0–4.4, and -reported `Cannot find module './renderHook.cjs'` with `skipLibCheck` off. They now have their real types: - -```ts -import { act, renderHook } from '@data-client/test'; - -const { result } = renderHook(() => 5); -result.current; // number -await act(() => Promise.resolve(5)); // number -``` diff --git a/.changeset/typescript7-exports.md b/.changeset/typescript7-exports.md deleted file mode 100644 index fa5015883d27..000000000000 --- a/.changeset/typescript7-exports.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@data-client/core': patch -'@data-client/endpoint': patch -'@data-client/graphql': patch -'@data-client/img': patch -'@data-client/normalizr': patch -'@data-client/react': patch -'@data-client/rest': patch -'@data-client/test': patch -'@data-client/vue': patch ---- - -Fix TypeScript 7 module resolution for package exports - -TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. diff --git a/.changeset/vue-create-data-client-internal.md b/.changeset/vue-create-data-client-internal.md deleted file mode 100644 index 0499b5909891..000000000000 --- a/.changeset/vue-create-data-client-internal.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@data-client/vue': patch ---- - -`createDataClient()` and `ProvidedDataClient` are deprecated - -They only exist to implement [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin) and will stop being -exported in a future release. Nothing changes at runtime. If you call `createDataClient()` directly, install the -plugin instead and read the controller with [useController()](https://dataclient.io/vue/api/useController). - -```ts title="main.ts" -import { DataClientPlugin } from '@data-client/vue'; - -app.use(DataClientPlugin, { managers, initialState }); -``` diff --git a/.changeset/vue-default-gcpolicy.md b/.changeset/vue-default-gcpolicy.md deleted file mode 100644 index 0bf139ffba2a..000000000000 --- a/.changeset/vue-default-gcpolicy.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@data-client/vue': patch ---- - -`DataClientPlugin` garbage collects by default - -Previously, unused data was only removed from the store if you passed a `gcPolicy` yourself. It now defaults -to `new GCPolicy()`, matching `DataProvider` in `@data-client/react`, so you can drop the option unless you -customize it. - -Before - -```ts -import { DataClientPlugin, GCPolicy } from '@data-client/vue'; - -app.use(DataClientPlugin, { gcPolicy: new GCPolicy() }); -``` - -After - -```ts -import { DataClientPlugin } from '@data-client/vue'; - -app.use(DataClientPlugin); -``` diff --git a/.changeset/vue-deprecate-wait-for-next-update.md b/.changeset/vue-deprecate-wait-for-next-update.md deleted file mode 100644 index 0bc08d01e146..000000000000 --- a/.changeset/vue-deprecate-wait-for-next-update.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -'@data-client/vue': patch ---- - -`waitForNextUpdate()` from `renderDataCompose()` is deprecated - -It gives up silently after 1 second, so a test could pass while the composable was still suspended. When the Promise -had already resolved, it waited the full second for nothing, and under `jest.useFakeTimers()` it could hang. Await the -result directly instead, and use `allSettled()` after changing props or calling the controller. - -`allSettled()` from `renderDataCompose()` and `mountDataClient()` now also waits for fetches that a prop change starts, -and for the component to re-render, so you no longer need `nextTick()` around it. It also waits on a `NetworkManager` -you pass in `managers`, instead of returning right away. - -#### Before - -```ts -import { reactive } from 'vue'; - -const props = reactive({ id: 5 }); -const { result, waitForNextUpdate } = await renderDataCompose( - (props: { id: number }) => - useSuspense(ArticleResource.get, () => ({ id: props.id })), - { props, resolverFixtures }, -); -await waitForNextUpdate(); -const article = await result; - -props.id = 6; -await waitForNextUpdate(); -``` - -#### After - -```ts -import { reactive } from 'vue'; - -const props = reactive({ id: 5 }); -const { result, allSettled } = await renderDataCompose( - (props: { id: number }) => - useSuspense(ArticleResource.get, () => ({ id: props.id })), - { props, resolverFixtures }, -); -const article = await result; - -props.id = 6; -await allSettled(); -``` diff --git a/.changeset/vue-expiry-stable.md b/.changeset/vue-expiry-stable.md deleted file mode 100644 index d1c04480c3cc..000000000000 --- a/.changeset/vue-expiry-stable.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix `useDLE()` and `useCache()` dropping expired `invalidIfStale` data on unrelated store updates - -After an `invalidIfStale` response expired, any unrelated store update switched these composables to empty data, and -`useDLE()` stayed `loading` without starting a fetch. Expiry is now only re-checked when the response's expiry, the -arguments, or a reset changes, matching `@data-client/react`. - -The `vue` peer dependency is now `^3.4.0`. - -```ts -const { data, loading } = useDLE(ArticleResource.get, { id: 5 }); -// ...after the response's dataExpiryLength passes -await ctrl.setResponse(UserResource.get, { id: 1 }, user); -// Before: loading.value === true, data.value === undefined, and no fetch starts -// After: loading.value === false, data.value is still the article -``` diff --git a/.changeset/vue-export-gcpolicy.md b/.changeset/vue-export-gcpolicy.md deleted file mode 100644 index be01e9cd5664..000000000000 --- a/.changeset/vue-export-gcpolicy.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Export `GCPolicy` from `@data-client/vue` - -```ts -// Before -import { GCPolicy } from '@data-client/core'; -// After -import { GCPolicy } from '@data-client/vue'; - -app.use(DataClientPlugin, { - gcPolicy: new GCPolicy({ intervalMS: 60 * 1000 * 10 }), -}); -``` diff --git a/.changeset/vue-getter-args.md b/.changeset/vue-getter-args.md deleted file mode 100644 index 6bbd4a387d7e..000000000000 --- a/.changeset/vue-getter-args.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix getter function arguments in Vue composables - -`useSuspense`, `useLive`, `useCache`, `useDLE`, `useFetch`, `useQuery` and `useSubscription` -were typed to accept getter functions as arguments, but only resolved refs at runtime. Getters -now work and are tracked reactively, just like refs and `computed`. - -```ts -const props = defineProps<{ id: number }>(); - -// Before: getter was passed to the endpoint as-is -// After: re-fetches when props.id changes -const article = await useSuspense(ArticleResource.get, () => ({ - id: props.id, -})); -``` diff --git a/.changeset/vue-plugin-onunmount.md b/.changeset/vue-plugin-onunmount.md deleted file mode 100644 index cb43925e503a..000000000000 --- a/.changeset/vue-plugin-onunmount.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix `app.use(DataClientPlugin)` throwing `app.onUnmount is not a function` on Vue versions before 3.5 - -```ts -const app = createApp(App); -// Before (Vue < 3.5): TypeError: app.onUnmount is not a function -// After: installs, and stops the DataClient when the app unmounts -app.use(DataClientPlugin); -``` diff --git a/.changeset/vue-stale-refetch.md b/.changeset/vue-stale-refetch.md deleted file mode 100644 index 7d50ffaf00d4..000000000000 --- a/.changeset/vue-stale-refetch.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix `useSuspense()`, `useDLE()` and `useFetch()` refetching stale data on every store update - -Once data was stale, any store update (such as `controller.set()`) made these composables refetch, so the server -response could overwrite the change. They now only refetch when the data's expiry, the arguments, or a reset changes, -matching `@data-client/react`. - -```ts -const article = await useSuspense(ArticleResource.get, { id: 5 }); -// ...after the response's dataExpiryLength passes -await ctrl.set(Article, { id: 5 }, { id: 5, title: 'edited' }); -// Before: triggers a refetch that reverts title to the server value -// After: title stays 'edited' -``` diff --git a/.changeset/vue-suspense-arg-errors.md b/.changeset/vue-suspense-arg-errors.md deleted file mode 100644 index 2006d403f3e7..000000000000 --- a/.changeset/vue-suspense-arg-errors.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix `useSuspense()` and `useLive()` fetch errors after arguments change being unhandled - -When ref or computed arguments changed and the new fetch failed, the error became an unhandled promise rejection -and the result became `undefined`. Reading the result now throws the error, like the first load does, so it reaches -`onErrorCaptured()`. - -```ts -const props = defineProps<{ id: number }>(); -const todo = await useSuspense( - TodoResource.get, - computed(() => ({ id: props.id })), -); -// Before: a failed fetch for a new id was an unhandled rejection; todo.value became undefined -// After: reading todo.value throws the fetch error, caught by onErrorCaptured() -``` diff --git a/.changeset/vue-suspense-keep-previous.md b/.changeset/vue-suspense-keep-previous.md deleted file mode 100644 index 5514d24bbc06..000000000000 --- a/.changeset/vue-suspense-keep-previous.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix `useSuspense()` and `useLive()` returning `undefined` while new arguments load - -When ref or computed arguments changed to data not yet in the store, the result became `undefined` until the -new fetch resolved, crashing templates like `{{ todo.title }}`. It now keeps the previous data until the new data arrives. - -```ts -const props = defineProps<{ id: number }>(); -const todo = await useSuspense(TodoResource.get, computed(() => ({ id: props.id }))); -// Before: todo.value was undefined while the new id loaded -// After: todo.value keeps the previous todo until the new one arrives -``` diff --git a/.changeset/vue-suspense-stale-while-revalidate.md b/.changeset/vue-suspense-stale-while-revalidate.md deleted file mode 100644 index 48a6b1470f03..000000000000 --- a/.changeset/vue-suspense-stale-while-revalidate.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix Vue `useSuspense()` suspending on stale data instead of showing it while it refetches - -When a component mounted with cached data that was past its `dataExpiryLength` but still valid, `await useSuspense()` -waited for the refetch, so users saw the `` fallback instead of the data already on hand. Now, like React, -it renders the stale data right away and updates once the refetch resolves. Data that is missing, invalidated, or -[invalidIfStale](https://dataclient.io/rest/api/Endpoint#invalidifstale) still waits for the fetch. diff --git a/.changeset/vue-usefetch-gc.md b/.changeset/vue-usefetch-gc.md deleted file mode 100644 index 53e34a097179..000000000000 --- a/.changeset/vue-usefetch-gc.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Vue `useFetch()` keeps its response from being garbage collected while mounted, like React `useFetch()` and Vue `useSuspense()` diff --git a/.changeset/vue-usefetch-ref-type.md b/.changeset/vue-usefetch-ref-type.md deleted file mode 100644 index efe2d3f82a2c..000000000000 --- a/.changeset/vue-usefetch-ref-type.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@data-client/vue': patch ---- - -Fix [useFetch()](https://dataclient.io/docs/api/useFetch) return type to be a read-only `Ref` - -`useFetch()` returns a read-only `Ref` holding the fetch promise, but was typed as returning the promise directly. - -```ts -const promise = useFetch(PostResource.get, { id }); -// Before: promise.resolved typechecked, but was always undefined at runtime -// After: -if (!promise.value.resolved) { - // fetch is in-flight -} -``` diff --git a/examples/benchmark-react/CHANGELOG.md b/examples/benchmark-react/CHANGELOG.md index ec05eb6974fe..31363a195bfe 100644 --- a/examples/benchmark-react/CHANGELOG.md +++ b/examples/benchmark-react/CHANGELOG.md @@ -1,5 +1,15 @@ # example-benchmark-react +## 0.1.12 + +### Patch Changes + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`a73b437`](https://github.com/reactive/data-client/commit/a73b437c8f60ef8c64266874ea82e5119dfe4874), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`954b1e9`](https://github.com/reactive/data-client/commit/954b1e9041ba47b39b9ffdd53a55b0b16adc8675), [`643d818`](https://github.com/reactive/data-client/commit/643d818ac757a0218e91d9523879e25024c5e61f), [`588a558`](https://github.com/reactive/data-client/commit/588a558332d9d2bc6a313b2f4b6700bb3ff017f2), [`bf377f4`](https://github.com/reactive/data-client/commit/bf377f46a2c916d8e808472645f1da9704ffaf91), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/core@1.0.0 + - @data-client/react@1.0.0 + - @data-client/endpoint@1.0.0 + - @data-client/rest@1.0.0 + ## 0.1.11 ### Patch Changes diff --git a/examples/benchmark-react/package.json b/examples/benchmark-react/package.json index eba10982123f..d0584f4d41d2 100644 --- a/examples/benchmark-react/package.json +++ b/examples/benchmark-react/package.json @@ -1,6 +1,6 @@ { "name": "example-benchmark-react", - "version": "0.1.11", + "version": "0.1.12", "private": true, "description": "React rendering benchmark comparing @data-client/react against other data libraries", "scripts": { diff --git a/examples/benchmark/CHANGELOG.md b/examples/benchmark/CHANGELOG.md index 257c96bafb41..a52a67fe7b7f 100644 --- a/examples/benchmark/CHANGELOG.md +++ b/examples/benchmark/CHANGELOG.md @@ -1,5 +1,14 @@ # example-benchmark +## 0.4.87 + +### Patch Changes + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/core@1.0.0 + - @data-client/endpoint@1.0.0 + - @data-client/normalizr@1.0.0 + ## 0.4.86 ### Patch Changes diff --git a/examples/benchmark/package.json b/examples/benchmark/package.json index 255c65a32269..50c40b4698ae 100644 --- a/examples/benchmark/package.json +++ b/examples/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "example-benchmark", - "version": "0.4.86", + "version": "0.4.87", "description": "Benchmark for normalizr", "main": "index.js", "author": "Nathaniel Tucker", diff --git a/examples/coin-app/CHANGELOG.md b/examples/coin-app/CHANGELOG.md index c9f467f6af27..343bc07e74ca 100644 --- a/examples/coin-app/CHANGELOG.md +++ b/examples/coin-app/CHANGELOG.md @@ -1,5 +1,14 @@ # coinbase-lite +## 0.0.27 + +### Patch Changes + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`a73b437`](https://github.com/reactive/data-client/commit/a73b437c8f60ef8c64266874ea82e5119dfe4874), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`954b1e9`](https://github.com/reactive/data-client/commit/954b1e9041ba47b39b9ffdd53a55b0b16adc8675), [`643d818`](https://github.com/reactive/data-client/commit/643d818ac757a0218e91d9523879e25024c5e61f), [`588a558`](https://github.com/reactive/data-client/commit/588a558332d9d2bc6a313b2f4b6700bb3ff017f2), [`bf377f4`](https://github.com/reactive/data-client/commit/bf377f46a2c916d8e808472645f1da9704ffaf91), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/react@1.0.0 + - @data-client/img@1.0.0 + - @data-client/rest@1.0.0 + ## 0.0.26 ### Patch Changes diff --git a/examples/coin-app/package.json b/examples/coin-app/package.json index d7ea8e642280..0a4e1cd8fe52 100644 --- a/examples/coin-app/package.json +++ b/examples/coin-app/package.json @@ -1,6 +1,6 @@ { "name": "coinbase-lite", - "version": "0.0.26", + "version": "0.0.27", "packageManager": "yarn@4.18.1", "description": "Coin App", "scripts": { @@ -45,9 +45,9 @@ "@anansi/core": "0.22.12", "@anansi/router": "0.10.24", "@babel/runtime-corejs3": "7.29.7", - "@data-client/img": "0.18.0", - "@data-client/react": "0.18.1", - "@data-client/rest": "0.18.1", + "@data-client/img": "1.0.0", + "@data-client/react": "1.0.0", + "@data-client/rest": "1.0.0", "core-js": "3.49.0", "d3": "7.9.0", "history": "*", diff --git a/examples/normalizr-github/CHANGELOG.md b/examples/normalizr-github/CHANGELOG.md index 89d77408ee04..93ea6f414e2c 100644 --- a/examples/normalizr-github/CHANGELOG.md +++ b/examples/normalizr-github/CHANGELOG.md @@ -1,5 +1,13 @@ # normalizr-github-example +## 0.1.61 + +### Patch Changes + +- Updated dependencies [[`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/endpoint@1.0.0 + - @data-client/normalizr@1.0.0 + ## 0.1.60 ### Patch Changes diff --git a/examples/normalizr-github/package.json b/examples/normalizr-github/package.json index 67574de10774..e8edfd919a89 100644 --- a/examples/normalizr-github/package.json +++ b/examples/normalizr-github/package.json @@ -1,6 +1,6 @@ { "name": "normalizr-github-example", - "version": "0.1.60", + "version": "0.1.61", "description": "And example of using Normalizr with github", "main": "index.js", "author": "Paul Armstrong", diff --git a/examples/normalizr-redux/CHANGELOG.md b/examples/normalizr-redux/CHANGELOG.md index 81b58d556372..181c58f81e71 100644 --- a/examples/normalizr-redux/CHANGELOG.md +++ b/examples/normalizr-redux/CHANGELOG.md @@ -1,5 +1,13 @@ # normalizr-redux-example +## 0.1.59 + +### Patch Changes + +- Updated dependencies [[`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/endpoint@1.0.0 + - @data-client/normalizr@1.0.0 + ## 0.1.58 ### Patch Changes diff --git a/examples/normalizr-redux/package.json b/examples/normalizr-redux/package.json index 50309c23a31a..ecf6791e0856 100644 --- a/examples/normalizr-redux/package.json +++ b/examples/normalizr-redux/package.json @@ -1,6 +1,6 @@ { "name": "normalizr-redux-example", - "version": "0.1.58", + "version": "0.1.59", "description": "And example of using Normalizr with Redux", "main": "index.js", "author": "Paul Armstrong", diff --git a/examples/normalizr-relationships/CHANGELOG.md b/examples/normalizr-relationships/CHANGELOG.md index e8c96a48c801..cc01d52be6da 100644 --- a/examples/normalizr-relationships/CHANGELOG.md +++ b/examples/normalizr-relationships/CHANGELOG.md @@ -1,5 +1,13 @@ # normalizr-relationships +## 0.1.61 + +### Patch Changes + +- Updated dependencies [[`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/endpoint@1.0.0 + - @data-client/normalizr@1.0.0 + ## 0.1.60 ### Patch Changes diff --git a/examples/normalizr-relationships/package.json b/examples/normalizr-relationships/package.json index 67db2b9a3d38..ab78c455ad16 100644 --- a/examples/normalizr-relationships/package.json +++ b/examples/normalizr-relationships/package.json @@ -1,6 +1,6 @@ { "name": "normalizr-relationships", - "version": "0.1.60", + "version": "0.1.61", "description": "And example of using Normalizr with relationships", "main": "index.js", "author": "Paul Armstrong", diff --git a/examples/test-bundlesize/CHANGELOG.md b/examples/test-bundlesize/CHANGELOG.md index 5ec2987e68b5..cd082173ed9c 100644 --- a/examples/test-bundlesize/CHANGELOG.md +++ b/examples/test-bundlesize/CHANGELOG.md @@ -1,5 +1,14 @@ # test-bundlesize +## 0.1.19 + +### Patch Changes + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`a73b437`](https://github.com/reactive/data-client/commit/a73b437c8f60ef8c64266874ea82e5119dfe4874), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`954b1e9`](https://github.com/reactive/data-client/commit/954b1e9041ba47b39b9ffdd53a55b0b16adc8675), [`643d818`](https://github.com/reactive/data-client/commit/643d818ac757a0218e91d9523879e25024c5e61f), [`588a558`](https://github.com/reactive/data-client/commit/588a558332d9d2bc6a313b2f4b6700bb3ff017f2), [`bf377f4`](https://github.com/reactive/data-client/commit/bf377f46a2c916d8e808472645f1da9704ffaf91), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/react@1.0.0 + - @data-client/img@1.0.0 + - @data-client/rest@1.0.0 + ## 0.1.18 ### Patch Changes diff --git a/examples/test-bundlesize/package.json b/examples/test-bundlesize/package.json index ff43067a49c9..02e064d8f218 100644 --- a/examples/test-bundlesize/package.json +++ b/examples/test-bundlesize/package.json @@ -1,6 +1,6 @@ { "name": "test-bundlesize", - "version": "0.1.18", + "version": "0.1.19", "packageManager": "yarn@4.18.1", "description": "Testing Bundled Size", "scripts": { diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index e01840bfa1f6..e678df540d75 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,180 @@ # @data-client/core +## 1.0.0 + +### Minor Changes + +- [#4151](https://github.com/reactive/data-client/pull/4151) [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e) - BREAKING: Require TypeScript 4.0 or later + + The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and + `@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. + + ```diff title="package.json" + - "typescript": "^3.9.0" + + "typescript": "^4.0.0" + ``` + +### Patch Changes + +- [#4103](https://github.com/reactive/data-client/pull/4103) [`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69) - Fix `controller.set()` types for Array schemas + + `controller.set([Entity], rows)` and `controller.set(new schema.Array(Entity), rows)` now typecheck. This writes every row in one store update: each row merges with its stored entity, and entities not in `rows` stay. + + Rows are typed by the Entity's fields. The schema holds one Entity, [Union](https://dataclient.io/rest/api/Union) (for mixed types) or [Invalidate](https://dataclient.io/rest/api/Invalidate) (to delete), in an Array or [Values](https://dataclient.io/rest/api/Values) (which takes an object keyed by id). + + Batch `set()` needs `@data-client/rest` (or `endpoint`/`graphql`) from this release, since older Entity classes don't type as `EntityInterface`. + + ```ts + // Before: TypeScript error on [Ticker], so batches became one set() per row + for (const row of rows) { + ctrl.set(Ticker, { product_id: row.product_id }, row); + } + + // After: one store update + ctrl.set([Ticker], rows); + + // Mixed Entity types, batch deletes, and rows keyed by id + const Message = new schema.Union({ ticker: Ticker, trade: Trade }, 'type'); + ctrl.set([Message], messages); + ctrl.set([new schema.Invalidate(Ticker)], [{ product_id: 'BTC-USD' }]); + ctrl.set(new schema.Values(Ticker), { 'BTC-USD': row }); + ``` + +- [#4230](https://github.com/reactive/data-client/pull/4230) [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c) - Fix `controller.set()` types for a single [Invalidate](https://dataclient.io/rest/api/Invalidate) + + Deleting one entity with `set()` worked at runtime but failed to typecheck, since `Invalidate` isn't + [Queryable](https://dataclient.io/rest/api/schema#queryable). Pass the schema and the row to delete; the row is typed + by the Entity's fields. + + ```ts + // Before: TypeScript error, so a one-row batch was the workaround + ctrl.set([new Invalidate(Post)], [{ id: '5' }]); + + // After + ctrl.set(new Invalidate(Post), { id: '5' }); + ``` + + Like batch `set()`, it takes no `args` and no updater function. + +- [#4133](https://github.com/reactive/data-client/pull/4133) [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18) - Fix `controller.set()` accepting any value + + Values are now typed by the schema: Entities take their fields, while [Collection](https://dataclient.io/rest/api/Collection) + and [All](https://dataclient.io/rest/api/All) take a list of rows. [Query](https://dataclient.io/rest/api/Query) takes + the input of the schema it wraps, not what its `process()` returns. Updater functions must return the same. + + ```ts + // Before: these all typechecked, then failed or wrote nothing at runtime + ctrl.set(new schema.All(Todo), 42); + ctrl.set(TodoResource.getList.schema, 'anything'); + ctrl.set(Todo, { id: '5' }, { id: '5', completed: 'yes' }); + + // After: TypeScript errors on the above; these typecheck + ctrl.set(TodoResource.getList.schema, [{ id: '5', completed: true }]); + ctrl.set(new schema.All(Todo), [{ id: '5', completed: true }]); + ``` + + When each member declares its discriminator as a literal (like `readonly type = 'post'`), a + [Union](https://dataclient.io/rest/api/Union) row is checked against the member it selects. Only + declared fields are accepted, so a key read by a `schemaAttribute` function must be declared on each member. + + ```ts + const Feed = new schema.Union({ post: Post, comment: Comment }, 'type'); + // TypeScript error: commentBody is a Comment field, not a Post field + ctrl.set( + Feed, + { id: '1', type: 'post' }, + { type: 'post', commentBody: 'hi' }, + ); + ``` + +- [#4228](https://github.com/reactive/data-client/pull/4228) [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee) - Fix TypeScript error passing a `Controller` subclass to `DataProvider` or `DataClientPlugin` + + A plain `class MyController extends Controller` failed to typecheck as the `Controller` option of [DataProvider](https://dataclient.io/docs/api/DataProvider#Controller), Vue's [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin#Controller), and the `@data-client/react/redux` `DataProvider`, so the documented example needed a cast. `MockController()` from `@data-client/core/mock` had the same error when wrapping your subclass. These now typecheck, and you can drop the casts. + + ```tsx + class MyController extends Controller { + doSomething = () => console.log('hi'); + } + + // Before: TypeScript error, so you had to cast + + app.use(DataClientPlugin, { Controller: MyController as typeof Controller }); + + // After + + app.use(DataClientPlugin, { Controller: MyController }); + ``` + +- [#4150](https://github.com/reactive/data-client/pull/4150) [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2) - Fix `useCache()` and `useDLE()` returning a truthy `Symbol` for deleted entities + + After an entity was deleted and its refetch failed, `useCache()` and `useDLE()` (React and Vue) returned an internal + `Symbol` instead of `undefined`. Since a `Symbol` is truthy, "not loaded" checks passed, and code went on to use it as + the entity: + + ```tsx + const todo = useCache(TodoResource.get, { id }); + if (!todo) return ; + // Before: reached here with a Symbol; todo.title was undefined and todo.title.trim() threw + // After: the placeholder renders + return ; + ``` + + [Controller.getResponse()](https://dataclient.io/docs/api/Controller#getResponse) and + [Controller.fetchIfStale()](https://dataclient.io/docs/api/Controller#fetchIfStale) now also give `undefined` there, + like [Controller.get()](https://dataclient.io/docs/api/Controller#get) already did. + +- [#4163](https://github.com/reactive/data-client/pull/4163) [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8) - Fix slow updates in development while Redux DevTools is open + + With the [Redux DevTools](https://dataclient.io/docs/getting-started/debugging) extension open, every store update + stalled the page while DevTools serialized the store: about 20ms with 50 entities, and 200ms with 500. Apps doing + many `controller.set()` calls, polling, or live updates would stutter in development. Each update now serializes + 40-60x faster, and timestamps still show as readable times like `10:42:07.123 AM`. + +- [#4227](https://github.com/reactive/data-client/pull/4227) [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d) - Type FETCH `action.meta.promise` as `Promise` + + Managers can now call `.finally()` and `.catch()` on a FETCH action's `meta.promise` without a TypeScript error. It was always a real `Promise` at runtime, but was typed `PromiseLike`, which only has `.then()`. + + ```ts + // Before: TypeScript error on .finally(), so both callbacks went to .then() + const track = () => + trackTiming(action.endpoint.name, performance.now() - start); + action.meta.promise.then(track, track); + + // After + action.meta.promise + .finally(() => { + trackTiming(action.endpoint.name, performance.now() - start); + }) + // the fetch's caller handles errors; this only observes timing + .catch(() => {}); + ``` + +- [#4250](https://github.com/reactive/data-client/pull/4250) [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a) - Fixture `args` accept readonly tuples + + Fixtures written with `args: [...] as const` now type-check when passed to [MockResolver](https://dataclient.io/docs/api/MockResolver), `renderDataHook()`, Vue's `renderDataCompose()` or `mockInitialState()`. Before, TypeScript rejected them with "The type 'readonly [...]' is 'readonly' and cannot be assigned to the mutable type", so you had to drop `as const` or cast. + + ```ts + const fixtures = [ + { + endpoint: TodoResource.getList, + args: [{ userId: 1 }] as const, + response: [{ id: 1, title: 'Write tests', userId: 1 }], + }, + ]; + + // Before: type error on `fixtures`. After: works as written + + + ; + ``` + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + +- Updated dependencies [[`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/normalizr@1.0.0 + ## 0.18.1 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index a59e09906151..a18bb5b76fca 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/core", - "version": "0.18.1", + "version": "1.0.0", "description": "Async State Management without the Management. REST, GraphQL, SSE, Websockets, Fetch", "sideEffects": false, "main": "dist/index.js", diff --git a/packages/endpoint/CHANGELOG.md b/packages/endpoint/CHANGELOG.md index d6d9ac031109..556238a54d97 100644 --- a/packages/endpoint/CHANGELOG.md +++ b/packages/endpoint/CHANGELOG.md @@ -1,5 +1,108 @@ # @data-client/endpoint +## 1.0.0 + +### Minor Changes + +- [#4151](https://github.com/reactive/data-client/pull/4151) [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e) - BREAKING: Require TypeScript 4.0 or later + + The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and + `@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. + + ```diff title="package.json" + - "typescript": "^3.9.0" + + "typescript": "^4.0.0" + ``` + +### Patch Changes + +- [#4149](https://github.com/reactive/data-client/pull/4149) [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e) - Fix Entity classes not assignable to `EntityInterface` + + [Entity.pk()](https://dataclient.io/rest/api/Entity#pk)'s static `args` parameter is now `readonly any[]`, matching `EntityInterface`. Entity classes can be passed where an `EntityInterface` is expected. + + ```ts + import type { EntityInterface } from '@data-client/react'; + + // Before: TypeScript error (args is readonly in EntityInterface) + // After: typechecks + const schema: EntityInterface = User; + ``` + + Overrides of `static pk()` that type `args` as a mutable array still compile, but a future breaking release will require `readonly any[]`, so update them now: + + ```ts + class User extends Entity { + static pk(value: any, parent?: any, key?: string, args?: readonly any[]) { + return `${value.id}-${args?.[0]?.org}`; + } + } + ``` + +- [#4173](https://github.com/reactive/data-client/pull/4173) [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7) - Speed up TypeScript checking of `RestEndpoint`, `resource()` and `.extend()` + + Editors and `tsc` check code that defines or calls endpoints faster and with less memory. In our stress tests, a file of 150 RestEndpoints with long paths, `.extend()` and `.paginated()` checked in about half the time (3.1s → 1.6s) and memory (345MB → 207MB). Files that use `resource()` with React or Vue hooks did 22-25% less type work. TypeScript reports the same errors as before. + + On TypeScript 5.x and earlier, a `process(value, params)` method passed to `.extend()` no longer fails with "implicitly has an 'any' type" under `strict`, matching TypeScript 6+. TypeScript 4.0 also accepts a chained `.extend().extend()`. + + ```ts + const getUser = new RestEndpoint({ path: '/users/:id', schema: User }); + + // Before (TypeScript 5.x and earlier): error TS7006: Parameter 'value' implicitly has an 'any' type. + // After: no error + const getUserName = getUser.extend({ + process(value, params) { + return value.name; + }, + }); + ``` + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix more TypeScript 4.x errors when `skipLibCheck` is off + + [Entity](https://dataclient.io/rest/api/Entity), [Endpoint](https://dataclient.io/rest/api/Endpoint), [Union](https://dataclient.io/rest/api/Union) and [RestEndpoint](https://dataclient.io/rest/api/RestEndpoint) declarations no longer report errors on TypeScript 4.0 through 4.5. On TypeScript 4.0 and 4.1, an `Entity` can be an `Endpoint` schema again. + + ```ts + import { Endpoint, Entity, schema } from '@data-client/endpoint'; + + class User extends Entity { + id = ''; + type = 'users'; + } + const getUser = new Endpoint( + (id: string) => fetch(`/users/${id}`).then(res => res.json()), + { schema: User }, + ); + const feed = new schema.Union({ users: User }, 'type'); + + // Before (TypeScript 4.0, skipLibCheck: false): + // error TS2456: Type alias 'RemoveArray' circularly references itself. + // error TS2322: Type 'typeof User' is not assignable to type 'EntityInterface'. + // Before (TypeScript 4.2): + // error TS2344: Type 'TBase' does not satisfy the constraint 'new (...args: any) => any'. + // After: no errors + ``` + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix types for TypeScript 4.x when `skipLibCheck` is off + + TypeScript 4.0 through 4.7 no longer report `Cannot find name 'NoInfer'` from `@data-client/endpoint` or `@data-client/normalizr`, and TypeScript 4.0 through 4.9 no longer report `Only named exports may use 'export type'` from `@data-client/normalizr`. + + ```ts + import { Entity } from '@data-client/endpoint'; + import { normalize } from '@data-client/normalizr'; + + // Before (TypeScript 4.7, skipLibCheck: false): + // error TS2304: Cannot find name 'NoInfer'. + // error TS1383: Only named exports may use 'export type'. + // After: no errors + ``` + +- [#4224](https://github.com/reactive/data-client/pull/4224) [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176) - Fix `Entity.maxEntityDepth` docs: the default is 64, not 128 + + Editor hover docs for `static maxEntityDepth` now show the real default. Runtime behavior is unchanged; set `maxEntityDepth` explicitly if you relied on 128. + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + ## 0.18.0 ### Minor Changes diff --git a/packages/endpoint/package.json b/packages/endpoint/package.json index edcdbd88c8e0..16629095ff22 100644 --- a/packages/endpoint/package.json +++ b/packages/endpoint/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/endpoint", - "version": "0.18.0", + "version": "1.0.0", "description": "Declarative Network Interface Definitions", "homepage": "https://dataclient.io/docs/guides/custom-protocol", "keywords": [ diff --git a/packages/graphql/CHANGELOG.md b/packages/graphql/CHANGELOG.md index 5fa37aaf13bd..036c22634320 100644 --- a/packages/graphql/CHANGELOG.md +++ b/packages/graphql/CHANGELOG.md @@ -1,5 +1,111 @@ # @data-client/graphql +## 1.0.0 + +### Minor Changes + +- [#4151](https://github.com/reactive/data-client/pull/4151) [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e) - BREAKING: Require TypeScript 4.0 or later + + The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and + `@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. + + ```diff title="package.json" + - "typescript": "^3.9.0" + + "typescript": "^4.0.0" + ``` + +### Patch Changes + +- [#4149](https://github.com/reactive/data-client/pull/4149) [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e) - Fix Entity classes not assignable to `EntityInterface` + + [Entity.pk()](https://dataclient.io/rest/api/Entity#pk)'s static `args` parameter is now `readonly any[]`, matching `EntityInterface`. Entity classes can be passed where an `EntityInterface` is expected. + + ```ts + import type { EntityInterface } from '@data-client/react'; + + // Before: TypeScript error (args is readonly in EntityInterface) + // After: typechecks + const schema: EntityInterface = User; + ``` + + Overrides of `static pk()` that type `args` as a mutable array still compile, but a future breaking release will require `readonly any[]`, so update them now: + + ```ts + class User extends Entity { + static pk(value: any, parent?: any, key?: string, args?: readonly any[]) { + return `${value.id}-${args?.[0]?.org}`; + } + } + ``` + +- [#4173](https://github.com/reactive/data-client/pull/4173) [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7) - Speed up TypeScript checking of `RestEndpoint`, `resource()` and `.extend()` + + Editors and `tsc` check code that defines or calls endpoints faster and with less memory. In our stress tests, a file of 150 RestEndpoints with long paths, `.extend()` and `.paginated()` checked in about half the time (3.1s → 1.6s) and memory (345MB → 207MB). Files that use `resource()` with React or Vue hooks did 22-25% less type work. TypeScript reports the same errors as before. + + On TypeScript 5.x and earlier, a `process(value, params)` method passed to `.extend()` no longer fails with "implicitly has an 'any' type" under `strict`, matching TypeScript 6+. TypeScript 4.0 also accepts a chained `.extend().extend()`. + + ```ts + const getUser = new RestEndpoint({ path: '/users/:id', schema: User }); + + // Before (TypeScript 5.x and earlier): error TS7006: Parameter 'value' implicitly has an 'any' type. + // After: no error + const getUserName = getUser.extend({ + process(value, params) { + return value.name; + }, + }); + ``` + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix more TypeScript 4.x errors when `skipLibCheck` is off + + [Entity](https://dataclient.io/rest/api/Entity), [Endpoint](https://dataclient.io/rest/api/Endpoint), [Union](https://dataclient.io/rest/api/Union) and [RestEndpoint](https://dataclient.io/rest/api/RestEndpoint) declarations no longer report errors on TypeScript 4.0 through 4.5. On TypeScript 4.0 and 4.1, an `Entity` can be an `Endpoint` schema again. + + ```ts + import { Endpoint, Entity, schema } from '@data-client/endpoint'; + + class User extends Entity { + id = ''; + type = 'users'; + } + const getUser = new Endpoint( + (id: string) => fetch(`/users/${id}`).then(res => res.json()), + { schema: User }, + ); + const feed = new schema.Union({ users: User }, 'type'); + + // Before (TypeScript 4.0, skipLibCheck: false): + // error TS2456: Type alias 'RemoveArray' circularly references itself. + // error TS2322: Type 'typeof User' is not assignable to type 'EntityInterface'. + // Before (TypeScript 4.2): + // error TS2344: Type 'TBase' does not satisfy the constraint 'new (...args: any) => any'. + // After: no errors + ``` + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix types for TypeScript 4.x when `skipLibCheck` is off + + TypeScript 4.0 through 4.7 no longer report `Cannot find name 'NoInfer'` from `@data-client/endpoint` or `@data-client/normalizr`, and TypeScript 4.0 through 4.9 no longer report `Only named exports may use 'export type'` from `@data-client/normalizr`. + + ```ts + import { Entity } from '@data-client/endpoint'; + import { normalize } from '@data-client/normalizr'; + + // Before (TypeScript 4.7, skipLibCheck: false): + // error TS2304: Cannot find name 'NoInfer'. + // error TS1383: Only named exports may use 'export type'. + // After: no errors + ``` + +- [#4224](https://github.com/reactive/data-client/pull/4224) [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176) - Fix `Entity.maxEntityDepth` docs: the default is 64, not 128 + + Editor hover docs for `static maxEntityDepth` now show the real default. Runtime behavior is unchanged; set `maxEntityDepth` explicitly if you relied on 128. + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + +- Updated dependencies [[`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/endpoint@1.0.0 + ## 0.18.0 ### Minor Changes diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 7fa643ea7f62..014f5261228e 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/graphql", - "version": "0.18.0", + "version": "1.0.0", "description": "Quickly define typed GraphQL resources and endpoints", "homepage": "https://dataclient.io/docs/graphql", "repository": { diff --git a/packages/img/CHANGELOG.md b/packages/img/CHANGELOG.md index 6d2724a68cb3..dc6154ada8d9 100644 --- a/packages/img/CHANGELOG.md +++ b/packages/img/CHANGELOG.md @@ -1,5 +1,29 @@ # @data-client/img +## 1.0.0 + +### Minor Changes + +- [#4151](https://github.com/reactive/data-client/pull/4151) [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e) - BREAKING: Require TypeScript 4.0 or later + + The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and + `@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. + + ```diff title="package.json" + - "typescript": "^3.9.0" + + "typescript": "^4.0.0" + ``` + +### Patch Changes + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`954b1e9`](https://github.com/reactive/data-client/commit/954b1e9041ba47b39b9ffdd53a55b0b16adc8675), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/react@1.0.0 + - @data-client/endpoint@1.0.0 + ## 0.18.0 ### Patch Changes diff --git a/packages/img/package.json b/packages/img/package.json index 2ae96324dd60..89632d6f89bc 100644 --- a/packages/img/package.json +++ b/packages/img/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/img", - "version": "0.18.0", + "version": "1.0.0", "description": "Suspenseful images", "homepage": "https://dataclient.io/docs/guides/img-media#just-images", "repository": { @@ -68,7 +68,7 @@ "@data-client/endpoint": "workspace:^" }, "peerDependencies": { - "@data-client/react": "^0.1.0 || ^0.2.0 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0", + "@data-client/react": "^1.0.0", "@types/react": "^16.14.0 || ^17.0.0 || ^18.0.0-0 || ^19.0.0", "react": "^16.14.0 || ^17.0.0 || ^18.0.0-0 || ^19.0.0" }, diff --git a/packages/normalizr/CHANGELOG.md b/packages/normalizr/CHANGELOG.md index ab480b23caf5..f7bf35847167 100644 --- a/packages/normalizr/CHANGELOG.md +++ b/packages/normalizr/CHANGELOG.md @@ -1,5 +1,39 @@ # Change Log +## 1.0.0 + +### Minor Changes + +- [#4151](https://github.com/reactive/data-client/pull/4151) [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e) - BREAKING: Require TypeScript 4.0 or later + + The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and + `@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. + + ```diff title="package.json" + - "typescript": "^3.9.0" + + "typescript": "^4.0.0" + ``` + +### Patch Changes + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix types for TypeScript 4.x when `skipLibCheck` is off + + TypeScript 4.0 through 4.7 no longer report `Cannot find name 'NoInfer'` from `@data-client/endpoint` or `@data-client/normalizr`, and TypeScript 4.0 through 4.9 no longer report `Only named exports may use 'export type'` from `@data-client/normalizr`. + + ```ts + import { Entity } from '@data-client/endpoint'; + import { normalize } from '@data-client/normalizr'; + + // Before (TypeScript 4.7, skipLibCheck: false): + // error TS2304: Cannot find name 'NoInfer'. + // error TS1383: Only named exports may use 'export type'. + // After: no errors + ``` + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + ## 0.18.1 ### Patch Changes diff --git a/packages/normalizr/package.json b/packages/normalizr/package.json index b63cc8897c64..5fe688021e03 100644 --- a/packages/normalizr/package.json +++ b/packages/normalizr/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/normalizr", - "version": "0.18.1", + "version": "1.0.0", "description": "Normalizes and denormalizes JSON according to schema for Redux and Flux applications", "homepage": "https://dataclient.io/docs/concepts/normalization", "keywords": [ diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index e2299e51147b..9c7c1464f378 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,230 @@ # @data-client/react +## 1.0.0 + +### Minor Changes + +- [#4151](https://github.com/reactive/data-client/pull/4151) [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e) - BREAKING: Require TypeScript 4.0 or later + + The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and + `@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. + + ```diff title="package.json" + - "typescript": "^3.9.0" + + "typescript": "^4.0.0" + ``` + +### Patch Changes + +- [#4103](https://github.com/reactive/data-client/pull/4103) [`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69) - Fix `controller.set()` types for Array schemas + + `controller.set([Entity], rows)` and `controller.set(new schema.Array(Entity), rows)` now typecheck. This writes every row in one store update: each row merges with its stored entity, and entities not in `rows` stay. + + Rows are typed by the Entity's fields. The schema holds one Entity, [Union](https://dataclient.io/rest/api/Union) (for mixed types) or [Invalidate](https://dataclient.io/rest/api/Invalidate) (to delete), in an Array or [Values](https://dataclient.io/rest/api/Values) (which takes an object keyed by id). + + Batch `set()` needs `@data-client/rest` (or `endpoint`/`graphql`) from this release, since older Entity classes don't type as `EntityInterface`. + + ```ts + // Before: TypeScript error on [Ticker], so batches became one set() per row + for (const row of rows) { + ctrl.set(Ticker, { product_id: row.product_id }, row); + } + + // After: one store update + ctrl.set([Ticker], rows); + + // Mixed Entity types, batch deletes, and rows keyed by id + const Message = new schema.Union({ ticker: Ticker, trade: Trade }, 'type'); + ctrl.set([Message], messages); + ctrl.set([new schema.Invalidate(Ticker)], [{ product_id: 'BTC-USD' }]); + ctrl.set(new schema.Values(Ticker), { 'BTC-USD': row }); + ``` + +- [#4230](https://github.com/reactive/data-client/pull/4230) [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c) - Fix `controller.set()` types for a single [Invalidate](https://dataclient.io/rest/api/Invalidate) + + Deleting one entity with `set()` worked at runtime but failed to typecheck, since `Invalidate` isn't + [Queryable](https://dataclient.io/rest/api/schema#queryable). Pass the schema and the row to delete; the row is typed + by the Entity's fields. + + ```ts + // Before: TypeScript error, so a one-row batch was the workaround + ctrl.set([new Invalidate(Post)], [{ id: '5' }]); + + // After + ctrl.set(new Invalidate(Post), { id: '5' }); + ``` + + Like batch `set()`, it takes no `args` and no updater function. + +- [#4133](https://github.com/reactive/data-client/pull/4133) [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18) - Fix `controller.set()` accepting any value + + Values are now typed by the schema: Entities take their fields, while [Collection](https://dataclient.io/rest/api/Collection) + and [All](https://dataclient.io/rest/api/All) take a list of rows. [Query](https://dataclient.io/rest/api/Query) takes + the input of the schema it wraps, not what its `process()` returns. Updater functions must return the same. + + ```ts + // Before: these all typechecked, then failed or wrote nothing at runtime + ctrl.set(new schema.All(Todo), 42); + ctrl.set(TodoResource.getList.schema, 'anything'); + ctrl.set(Todo, { id: '5' }, { id: '5', completed: 'yes' }); + + // After: TypeScript errors on the above; these typecheck + ctrl.set(TodoResource.getList.schema, [{ id: '5', completed: true }]); + ctrl.set(new schema.All(Todo), [{ id: '5', completed: true }]); + ``` + + When each member declares its discriminator as a literal (like `readonly type = 'post'`), a + [Union](https://dataclient.io/rest/api/Union) row is checked against the member it selects. Only + declared fields are accepted, so a key read by a `schemaAttribute` function must be declared on each member. + + ```ts + const Feed = new schema.Union({ post: Post, comment: Comment }, 'type'); + // TypeScript error: commentBody is a Comment field, not a Post field + ctrl.set( + Feed, + { id: '1', type: 'post' }, + { type: 'post', commentBody: 'hi' }, + ); + ``` + +- [#4228](https://github.com/reactive/data-client/pull/4228) [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee) - Fix TypeScript error passing a `Controller` subclass to `DataProvider` or `DataClientPlugin` + + A plain `class MyController extends Controller` failed to typecheck as the `Controller` option of [DataProvider](https://dataclient.io/docs/api/DataProvider#Controller), Vue's [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin#Controller), and the `@data-client/react/redux` `DataProvider`, so the documented example needed a cast. `MockController()` from `@data-client/core/mock` had the same error when wrapping your subclass. These now typecheck, and you can drop the casts. + + ```tsx + class MyController extends Controller { + doSomething = () => console.log('hi'); + } + + // Before: TypeScript error, so you had to cast + + app.use(DataClientPlugin, { Controller: MyController as typeof Controller }); + + // After + + app.use(DataClientPlugin, { Controller: MyController }); + ``` + +- [#4150](https://github.com/reactive/data-client/pull/4150) [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2) - Fix `useCache()` and `useDLE()` returning a truthy `Symbol` for deleted entities + + After an entity was deleted and its refetch failed, `useCache()` and `useDLE()` (React and Vue) returned an internal + `Symbol` instead of `undefined`. Since a `Symbol` is truthy, "not loaded" checks passed, and code went on to use it as + the entity: + + ```tsx + const todo = useCache(TodoResource.get, { id }); + if (!todo) return ; + // Before: reached here with a Symbol; todo.title was undefined and todo.title.trim() threw + // After: the placeholder renders + return ; + ``` + + [Controller.getResponse()](https://dataclient.io/docs/api/Controller#getResponse) and + [Controller.fetchIfStale()](https://dataclient.io/docs/api/Controller#fetchIfStale) now also give `undefined` there, + like [Controller.get()](https://dataclient.io/docs/api/Controller#get) already did. + +- [#4163](https://github.com/reactive/data-client/pull/4163) [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8) - Fix slow updates in development while Redux DevTools is open + + With the [Redux DevTools](https://dataclient.io/docs/getting-started/debugging) extension open, every store update + stalled the page while DevTools serialized the store: about 20ms with 50 entities, and 200ms with 500. Apps doing + many `controller.set()` calls, polling, or live updates would stutter in development. Each update now serializes + 40-60x faster, and timestamps still show as readable times like `10:42:07.123 AM`. + +- [#4227](https://github.com/reactive/data-client/pull/4227) [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d) - Type FETCH `action.meta.promise` as `Promise` + + Managers can now call `.finally()` and `.catch()` on a FETCH action's `meta.promise` without a TypeScript error. It was always a real `Promise` at runtime, but was typed `PromiseLike`, which only has `.then()`. + + ```ts + // Before: TypeScript error on .finally(), so both callbacks went to .then() + const track = () => + trackTiming(action.endpoint.name, performance.now() - start); + action.meta.promise.then(track, track); + + // After + action.meta.promise + .finally(() => { + trackTiming(action.endpoint.name, performance.now() - start); + }) + // the fetch's caller handles errors; this only observes timing + .catch(() => {}); + ``` + +- [#4250](https://github.com/reactive/data-client/pull/4250) [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a) - Fixture `args` accept readonly tuples + + Fixtures written with `args: [...] as const` now type-check when passed to [MockResolver](https://dataclient.io/docs/api/MockResolver), `renderDataHook()`, Vue's `renderDataCompose()` or `mockInitialState()`. Before, TypeScript rejected them with "The type 'readonly [...]' is 'readonly' and cannot be assigned to the mutable type", so you had to drop `as const` or cast. + + ```ts + const fixtures = [ + { + endpoint: TodoResource.getList, + args: [{ userId: 1 }] as const, + response: [{ id: 1, title: 'Write tests', userId: 1 }], + }, + ]; + + // Before: type error on `fixtures`. After: works as written + + + ; + ``` + +- [#4232](https://github.com/reactive/data-client/pull/4232) [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9) - Fix `',' expected` errors on TypeScript 4.0 through 4.4 + + Importing `@data-client/react/redux`, `@data-client/react/nextjs` or `@data-client/test` failed to compile on TypeScript before 4.5, even with `skipLibCheck` on, because their declaration files used syntax those versions can't parse. They now compile on TypeScript 4.0 and later. + + ```ts + import { DataProvider } from '@data-client/react/nextjs'; + import { renderDataHook } from '@data-client/test'; + + // Before (TypeScript 4.0 to 4.4): + // node_modules/@data-client/react/lib/server/nextjs/DataProvider/DataProvider.d.ts(1,15): error TS1005: ',' expected. + // node_modules/@data-client/test/lib/makeRenderDataClient/index.d.ts(3,33): error TS1005: ',' expected. + // After: no errors + ``` + + `@data-client/vue/test` types now also resolve with `moduleResolution: "node"`. + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix types for TypeScript 4.x when `skipLibCheck` is off + + TypeScript 4.0 through 4.7 no longer report `Cannot find name 'NoInfer'` from `@data-client/endpoint` or `@data-client/normalizr`, and TypeScript 4.0 through 4.9 no longer report `Only named exports may use 'export type'` from `@data-client/normalizr`. + + ```ts + import { Entity } from '@data-client/endpoint'; + import { normalize } from '@data-client/normalizr'; + + // Before (TypeScript 4.7, skipLibCheck: false): + // error TS2304: Cannot find name 'NoInfer'. + // error TS1383: Only named exports may use 'export type'. + // After: no errors + ``` + +- [#4238](https://github.com/reactive/data-client/pull/4238) [`954b1e9`](https://github.com/reactive/data-client/commit/954b1e9041ba47b39b9ffdd53a55b0b16adc8675) - Fix TypeScript error passing `prepareStore()`'s store to react-redux's `` + + `prepareStore()` from `@data-client/react/redux` typed its `store` as a minimal object with only `getState()` and `subscribe()`, so [using it with React-Redux](https://dataclient.io/docs/guides/redux) needed a cast, and `store.dispatch()` was a TypeScript error. It's now typed as a Redux `Store`. Its `replaceReducer()` and `[Symbol.observable]()` aren't supported: they throw, and are typed as returning `never`. + + ```tsx + const { store, selector, controller } = prepareStore( + initialState, + managers, + Controller, + otherReducers, + extraMiddlewares, + ); + + // Before: TypeScript error, so you had to cast + + + // After + + ``` + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/core@1.0.0 + ## 0.18.1 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index eedcd6bdb1f0..93960b59b6aa 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/react", - "version": "0.18.1", + "version": "1.0.0", "description": "Async State Management without the Management. REST, GraphQL, SSE, Websockets, Fetch", "homepage": "https://dataclient.io", "repository": { diff --git a/packages/rest/CHANGELOG.md b/packages/rest/CHANGELOG.md index 97852fc799b3..0926e21c24a0 100644 --- a/packages/rest/CHANGELOG.md +++ b/packages/rest/CHANGELOG.md @@ -1,5 +1,178 @@ # @data-client/rest +## 1.0.0 + +### Patch Changes + +- [#4149](https://github.com/reactive/data-client/pull/4149) [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e) - Fix Entity classes not assignable to `EntityInterface` + + [Entity.pk()](https://dataclient.io/rest/api/Entity#pk)'s static `args` parameter is now `readonly any[]`, matching `EntityInterface`. Entity classes can be passed where an `EntityInterface` is expected. + + ```ts + import type { EntityInterface } from '@data-client/react'; + + // Before: TypeScript error (args is readonly in EntityInterface) + // After: typechecks + const schema: EntityInterface = User; + ``` + + Overrides of `static pk()` that type `args` as a mutable array still compile, but a future breaking release will require `readonly any[]`, so update them now: + + ```ts + class User extends Entity { + static pk(value: any, parent?: any, key?: string, args?: readonly any[]) { + return `${value.id}-${args?.[0]?.org}`; + } + } + ``` + +- [#4183](https://github.com/reactive/data-client/pull/4183) [`a73b437`](https://github.com/reactive/data-client/commit/a73b437c8f60ef8c64266874ea82e5119dfe4874) - Type the `params` and `body` that `process()` receives in `RestEndpoint` options + + A `process(value, params)` method passed to `new RestEndpoint()`, `RestEndpoint.extend()` or `resource().extend()` used to get `params` typed as `any`, so a typo or a wrong assumption about a path parameter went unnoticed until runtime. They are now typed from the endpoint's `path`, `searchParams` and `body`, including a `path` set in the same `.extend()` call. + + ```ts + const getUser = new RestEndpoint({ path: '/users/:id' }); + + const getUserById = getUser.extend({ + path: '/users/by-id/:userId', + process(value, params) { + params.userId; // string | number + params.id; // TypeScript error: 'id' is not a param of '/users/by-id/:userId' + return value; + }, + }); + ``` + + Endpoints whose params are optional pass `params` as possibly `undefined`, so read it with `params?.page`. + + This can surface new TypeScript errors in existing `process()` methods that read a param the endpoint doesn't have, or that read optional `params` without a check. Each is a read that could be `undefined` or throw at runtime, so fix the param name or add the check. + + On TypeScript 5.x and earlier, `process(value, params)` in an `.extend()` that also sets `path` no longer fails with "implicitly has an 'any' type" under `strict`. + +- [#4173](https://github.com/reactive/data-client/pull/4173) [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7) - Speed up TypeScript checking of `RestEndpoint`, `resource()` and `.extend()` + + Editors and `tsc` check code that defines or calls endpoints faster and with less memory. In our stress tests, a file of 150 RestEndpoints with long paths, `.extend()` and `.paginated()` checked in about half the time (3.1s → 1.6s) and memory (345MB → 207MB). Files that use `resource()` with React or Vue hooks did 22-25% less type work. TypeScript reports the same errors as before. + + On TypeScript 5.x and earlier, a `process(value, params)` method passed to `.extend()` no longer fails with "implicitly has an 'any' type" under `strict`, matching TypeScript 6+. TypeScript 4.0 also accepts a chained `.extend().extend()`. + + ```ts + const getUser = new RestEndpoint({ path: '/users/:id', schema: User }); + + // Before (TypeScript 5.x and earlier): error TS7006: Parameter 'value' implicitly has an 'any' type. + // After: no error + const getUserName = getUser.extend({ + process(value, params) { + return value.name; + }, + }); + ``` + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix more TypeScript 4.x errors when `skipLibCheck` is off + + [Entity](https://dataclient.io/rest/api/Entity), [Endpoint](https://dataclient.io/rest/api/Endpoint), [Union](https://dataclient.io/rest/api/Union) and [RestEndpoint](https://dataclient.io/rest/api/RestEndpoint) declarations no longer report errors on TypeScript 4.0 through 4.5. On TypeScript 4.0 and 4.1, an `Entity` can be an `Endpoint` schema again. + + ```ts + import { Endpoint, Entity, schema } from '@data-client/endpoint'; + + class User extends Entity { + id = ''; + type = 'users'; + } + const getUser = new Endpoint( + (id: string) => fetch(`/users/${id}`).then(res => res.json()), + { schema: User }, + ); + const feed = new schema.Union({ users: User }, 'type'); + + // Before (TypeScript 4.0, skipLibCheck: false): + // error TS2456: Type alias 'RemoveArray' circularly references itself. + // error TS2322: Type 'typeof User' is not assignable to type 'EntityInterface'. + // Before (TypeScript 4.2): + // error TS2344: Type 'TBase' does not satisfy the constraint 'new (...args: any) => any'. + // After: no errors + ``` + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix types for TypeScript 4.x when `skipLibCheck` is off + + TypeScript 4.0 through 4.7 no longer report `Cannot find name 'NoInfer'` from `@data-client/endpoint` or `@data-client/normalizr`, and TypeScript 4.0 through 4.9 no longer report `Only named exports may use 'export type'` from `@data-client/normalizr`. + + ```ts + import { Entity } from '@data-client/endpoint'; + import { normalize } from '@data-client/normalizr'; + + // Before (TypeScript 4.7, skipLibCheck: false): + // error TS2304: Cannot find name 'NoInfer'. + // error TS1383: Only named exports may use 'export type'. + // After: no errors + ``` + +- [#4224](https://github.com/reactive/data-client/pull/4224) [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176) - Fix `Entity.maxEntityDepth` docs: the default is 64, not 128 + + Editor hover docs for `static maxEntityDepth` now show the real default. Runtime behavior is unchanged; set `maxEntityDepth` explicitly if you relied on 128. + +- [#4226](https://github.com/reactive/data-client/pull/4226) [`643d818`](https://github.com/reactive/data-client/commit/643d818ac757a0218e91d9523879e25024c5e61f) - Fix `RestEndpoint.push`, `unshift` and `remove` body types when a `Query` or `Lazy` wraps the endpoint's `Collection` + + Sorting or filtering a list with a [Query](https://dataclient.io/rest/api/Query) around its [Collection](https://dataclient.io/rest/api/Collection) made `getPosts.push` reject every body except `FormData`, though it adds to the list at runtime. The body is now typed from the Collection's Entity, so a correct body compiles and a wrong field is a TypeScript error. The same applies to a Collection wrapped in [Lazy](https://dataclient.io/rest/api/Lazy). + + ```ts + const getPosts = new RestEndpoint({ + path: '/:group/posts', + searchParams: {} as { orderBy?: string }, + schema: new Query( + new Collection([Post], { nonFilterArgumentKeys: /orderBy/ }), + (posts, { orderBy } = {}) => sortBy(posts, orderBy), + ), + }); + ``` + + If you cast the body to get past this error, the cast can go: + + ```ts + // Before + ctrl.fetch(getPosts.push, { group: 'react' }, { title, author } as any); + // After + ctrl.fetch(getPosts.push, { group: 'react' }, { title, author }); + ``` + +- [#4235](https://github.com/reactive/data-client/pull/4235) [`588a558`](https://github.com/reactive/data-client/commit/588a558332d9d2bc6a313b2f4b6700bb3ff017f2) - Fix TypeScript error passing `FormData` to `resource().create` + + `resource().create` sends a `FormData` body as-is, the same as `update`, `partialUpdate` and + `getList.push`, but its type only allowed an object, so submitting a form needed a cast. This now typechecks, + and you can drop the cast. `create` is deprecated, and its replacement `getList.push` takes `FormData` too. + + ```tsx + { + e.preventDefault(); + // Before: TypeScript error, so you had to cast + ctrl.fetch(PostResource.create, new FormData(e.currentTarget) as any); + // After + ctrl.fetch(PostResource.create, new FormData(e.currentTarget)); + }} + > + ``` + +- [#4184](https://github.com/reactive/data-client/pull/4184) [`bf377f4`](https://github.com/reactive/data-client/commit/bf377f46a2c916d8e808472645f1da9704ffaf91) - Fix `resource().extend({ get: ... })` dropping endpoints added earlier from its type + + Customizing a resource's standard endpoints with `.extend({ ... })` kept every endpoint at runtime, but TypeScript lost the ones added before it with `.extend('name', options)`, and the deprecated `create`. Using them was a type error even though they worked. + + ```ts + const UserResource = resource({ path: '/users/:id', schema: User }) + .extend('current', { path: '/user' }) + .extend({ get: { dataExpiryLength: 60000 } }); + + // Before: Property 'current' does not exist + // After: no error + const me = await ctrl.fetch(UserResource.current); + ``` + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + +- Updated dependencies [[`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`cc57a77`](https://github.com/reactive/data-client/commit/cc57a77d2e563071926f50cb9054516d2ab9101e), [`022f449`](https://github.com/reactive/data-client/commit/022f44950bf687b61f2d349e42ab906071c6fce7), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`a403df8`](https://github.com/reactive/data-client/commit/a403df8f22dadb0dbd9a6cf72a65f9187ae63176), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/endpoint@1.0.0 + ## 0.18.1 ### Patch Changes diff --git a/packages/rest/package.json b/packages/rest/package.json index 5faf4e204233..e7c65246ec0c 100644 --- a/packages/rest/package.json +++ b/packages/rest/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/rest", - "version": "0.18.1", + "version": "1.0.0", "description": "Quickly define typed REST resources and endpoints", "homepage": "https://dataclient.io/rest", "repository": { diff --git a/packages/test/CHANGELOG.md b/packages/test/CHANGELOG.md index 0a4a4d01c311..8ece572bb86a 100644 --- a/packages/test/CHANGELOG.md +++ b/packages/test/CHANGELOG.md @@ -1,5 +1,98 @@ # @data-client/test +## 1.0.0 + +### Minor Changes + +- [#4151](https://github.com/reactive/data-client/pull/4151) [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e) - BREAKING: Require TypeScript 4.0 or later + + The TypeScript 3.x type declarations are removed. They no longer type-checked on any TypeScript 3.x version, and + `@data-client/rest` already required TypeScript 4.0. Upgrade TypeScript to 4.0 or later. + + ```diff title="package.json" + - "typescript": "^3.9.0" + + "typescript": "^4.0.0" + ``` + +### Patch Changes + +- [#4228](https://github.com/reactive/data-client/pull/4228) [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee) - Fix TypeScript error passing a `Controller` subclass to `DataProvider` or `DataClientPlugin` + + A plain `class MyController extends Controller` failed to typecheck as the `Controller` option of [DataProvider](https://dataclient.io/docs/api/DataProvider#Controller), Vue's [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin#Controller), and the `@data-client/react/redux` `DataProvider`, so the documented example needed a cast. `MockController()` from `@data-client/core/mock` had the same error when wrapping your subclass. These now typecheck, and you can drop the casts. + + ```tsx + class MyController extends Controller { + doSomething = () => console.log('hi'); + } + + // Before: TypeScript error, so you had to cast + + app.use(DataClientPlugin, { Controller: MyController as typeof Controller }); + + // After + + app.use(DataClientPlugin, { Controller: MyController }); + ``` + +- [#4250](https://github.com/reactive/data-client/pull/4250) [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a) - Fixture `args` accept readonly tuples + + Fixtures written with `args: [...] as const` now type-check when passed to [MockResolver](https://dataclient.io/docs/api/MockResolver), `renderDataHook()`, Vue's `renderDataCompose()` or `mockInitialState()`. Before, TypeScript rejected them with "The type 'readonly [...]' is 'readonly' and cannot be assigned to the mutable type", so you had to drop `as const` or cast. + + ```ts + const fixtures = [ + { + endpoint: TodoResource.getList, + args: [{ userId: 1 }] as const, + response: [{ id: 1, title: 'Write tests', userId: 1 }], + }, + ]; + + // Before: type error on `fixtures`. After: works as written + + + ; + ``` + +- [#4232](https://github.com/reactive/data-client/pull/4232) [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9) - Fix `',' expected` errors on TypeScript 4.0 through 4.4 + + Importing `@data-client/react/redux`, `@data-client/react/nextjs` or `@data-client/test` failed to compile on TypeScript before 4.5, even with `skipLibCheck` on, because their declaration files used syntax those versions can't parse. They now compile on TypeScript 4.0 and later. + + ```ts + import { DataProvider } from '@data-client/react/nextjs'; + import { renderDataHook } from '@data-client/test'; + + // Before (TypeScript 4.0 to 4.4): + // node_modules/@data-client/react/lib/server/nextjs/DataProvider/DataProvider.d.ts(1,15): error TS1005: ',' expected. + // node_modules/@data-client/test/lib/makeRenderDataClient/index.d.ts(3,33): error TS1005: ',' expected. + // After: no errors + ``` + + `@data-client/vue/test` types now also resolve with `moduleResolution: "node"`. + +- [#4099](https://github.com/reactive/data-client/pull/4099) [`4ae6080`](https://github.com/reactive/data-client/commit/4ae608081ed33c6ce5ab3c0032276cc3069311f8) - Fix mount effects when `renderDataHook()` suspends on the first render + + `renderDataHook()` and `makeRenderDataHook()` now run provider mount effects when the first render suspends, including `use(useFetch())`. The hook result stays unresolved until the data arrives. + +- [#4251](https://github.com/reactive/data-client/pull/4251) [`dc84c02`](https://github.com/reactive/data-client/commit/dc84c02853fd4adafd79c1c96636c259df04abf7) - Fix `act` and `renderHook` typed as `any` on TypeScript 4.0–4.4 + + `act()`, `renderHook()` and `RenderHookOptions` from `@data-client/test` were `any` on TypeScript 4.0–4.4, and + reported `Cannot find module './renderHook.cjs'` with `skipLibCheck` off. They now have their real types: + + ```ts + import { act, renderHook } from '@data-client/test'; + + const { result } = renderHook(() => 5); + result.current; // number + await act(() => Promise.resolve(5)); // number + ``` + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9), [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc), [`954b1e9`](https://github.com/reactive/data-client/commit/954b1e9041ba47b39b9ffdd53a55b0b16adc8675), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/react@1.0.0 + ## 0.18.0 ### Patch Changes diff --git a/packages/test/package.json b/packages/test/package.json index f01ae8ac4919..5e2284f093c2 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/test", - "version": "0.18.0", + "version": "1.0.0", "description": "Testing utilities for Data Client", "homepage": "https://dataclient.io/docs/guides/storybook", "repository": { @@ -109,7 +109,7 @@ "@testing-library/react": "^16.0.0" }, "peerDependencies": { - "@data-client/react": "^0.12.15 || ^0.13.0 || ^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0", + "@data-client/react": "^1.0.0", "@testing-library/react-hooks": "^8.0.0", "@testing-library/react-native": "^13.0.0", "@types/react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-0 || ^19.0.0", diff --git a/packages/vue/CHANGELOG.md b/packages/vue/CHANGELOG.md index 0e98e16ab9b1..524ea26b99da 100644 --- a/packages/vue/CHANGELOG.md +++ b/packages/vue/CHANGELOG.md @@ -1,5 +1,398 @@ # @data-client/vue +## 1.0.0 + +### Patch Changes + +- [#4103](https://github.com/reactive/data-client/pull/4103) [`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69) - Fix `controller.set()` types for Array schemas + + `controller.set([Entity], rows)` and `controller.set(new schema.Array(Entity), rows)` now typecheck. This writes every row in one store update: each row merges with its stored entity, and entities not in `rows` stay. + + Rows are typed by the Entity's fields. The schema holds one Entity, [Union](https://dataclient.io/rest/api/Union) (for mixed types) or [Invalidate](https://dataclient.io/rest/api/Invalidate) (to delete), in an Array or [Values](https://dataclient.io/rest/api/Values) (which takes an object keyed by id). + + Batch `set()` needs `@data-client/rest` (or `endpoint`/`graphql`) from this release, since older Entity classes don't type as `EntityInterface`. + + ```ts + // Before: TypeScript error on [Ticker], so batches became one set() per row + for (const row of rows) { + ctrl.set(Ticker, { product_id: row.product_id }, row); + } + + // After: one store update + ctrl.set([Ticker], rows); + + // Mixed Entity types, batch deletes, and rows keyed by id + const Message = new schema.Union({ ticker: Ticker, trade: Trade }, 'type'); + ctrl.set([Message], messages); + ctrl.set([new schema.Invalidate(Ticker)], [{ product_id: 'BTC-USD' }]); + ctrl.set(new schema.Values(Ticker), { 'BTC-USD': row }); + ``` + +- [#4230](https://github.com/reactive/data-client/pull/4230) [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c) - Fix `controller.set()` types for a single [Invalidate](https://dataclient.io/rest/api/Invalidate) + + Deleting one entity with `set()` worked at runtime but failed to typecheck, since `Invalidate` isn't + [Queryable](https://dataclient.io/rest/api/schema#queryable). Pass the schema and the row to delete; the row is typed + by the Entity's fields. + + ```ts + // Before: TypeScript error, so a one-row batch was the workaround + ctrl.set([new Invalidate(Post)], [{ id: '5' }]); + + // After + ctrl.set(new Invalidate(Post), { id: '5' }); + ``` + + Like batch `set()`, it takes no `args` and no updater function. + +- [#4133](https://github.com/reactive/data-client/pull/4133) [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18) - Fix `controller.set()` accepting any value + + Values are now typed by the schema: Entities take their fields, while [Collection](https://dataclient.io/rest/api/Collection) + and [All](https://dataclient.io/rest/api/All) take a list of rows. [Query](https://dataclient.io/rest/api/Query) takes + the input of the schema it wraps, not what its `process()` returns. Updater functions must return the same. + + ```ts + // Before: these all typechecked, then failed or wrote nothing at runtime + ctrl.set(new schema.All(Todo), 42); + ctrl.set(TodoResource.getList.schema, 'anything'); + ctrl.set(Todo, { id: '5' }, { id: '5', completed: 'yes' }); + + // After: TypeScript errors on the above; these typecheck + ctrl.set(TodoResource.getList.schema, [{ id: '5', completed: true }]); + ctrl.set(new schema.All(Todo), [{ id: '5', completed: true }]); + ``` + + When each member declares its discriminator as a literal (like `readonly type = 'post'`), a + [Union](https://dataclient.io/rest/api/Union) row is checked against the member it selects. Only + declared fields are accepted, so a key read by a `schemaAttribute` function must be declared on each member. + + ```ts + const Feed = new schema.Union({ post: Post, comment: Comment }, 'type'); + // TypeScript error: commentBody is a Comment field, not a Post field + ctrl.set( + Feed, + { id: '1', type: 'post' }, + { type: 'post', commentBody: 'hi' }, + ); + ``` + +- [#4228](https://github.com/reactive/data-client/pull/4228) [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee) - Fix TypeScript error passing a `Controller` subclass to `DataProvider` or `DataClientPlugin` + + A plain `class MyController extends Controller` failed to typecheck as the `Controller` option of [DataProvider](https://dataclient.io/docs/api/DataProvider#Controller), Vue's [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin#Controller), and the `@data-client/react/redux` `DataProvider`, so the documented example needed a cast. `MockController()` from `@data-client/core/mock` had the same error when wrapping your subclass. These now typecheck, and you can drop the casts. + + ```tsx + class MyController extends Controller { + doSomething = () => console.log('hi'); + } + + // Before: TypeScript error, so you had to cast + + app.use(DataClientPlugin, { Controller: MyController as typeof Controller }); + + // After + + app.use(DataClientPlugin, { Controller: MyController }); + ``` + +- [#4150](https://github.com/reactive/data-client/pull/4150) [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2) - Fix `useCache()` and `useDLE()` returning a truthy `Symbol` for deleted entities + + After an entity was deleted and its refetch failed, `useCache()` and `useDLE()` (React and Vue) returned an internal + `Symbol` instead of `undefined`. Since a `Symbol` is truthy, "not loaded" checks passed, and code went on to use it as + the entity: + + ```tsx + const todo = useCache(TodoResource.get, { id }); + if (!todo) return ; + // Before: reached here with a Symbol; todo.title was undefined and todo.title.trim() threw + // After: the placeholder renders + return ; + ``` + + [Controller.getResponse()](https://dataclient.io/docs/api/Controller#getResponse) and + [Controller.fetchIfStale()](https://dataclient.io/docs/api/Controller#fetchIfStale) now also give `undefined` there, + like [Controller.get()](https://dataclient.io/docs/api/Controller#get) already did. + +- [#4163](https://github.com/reactive/data-client/pull/4163) [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8) - Fix slow updates in development while Redux DevTools is open + + With the [Redux DevTools](https://dataclient.io/docs/getting-started/debugging) extension open, every store update + stalled the page while DevTools serialized the store: about 20ms with 50 entities, and 200ms with 500. Apps doing + many `controller.set()` calls, polling, or live updates would stutter in development. Each update now serializes + 40-60x faster, and timestamps still show as readable times like `10:42:07.123 AM`. + +- [#4227](https://github.com/reactive/data-client/pull/4227) [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d) - Type FETCH `action.meta.promise` as `Promise` + + Managers can now call `.finally()` and `.catch()` on a FETCH action's `meta.promise` without a TypeScript error. It was always a real `Promise` at runtime, but was typed `PromiseLike`, which only has `.then()`. + + ```ts + // Before: TypeScript error on .finally(), so both callbacks went to .then() + const track = () => + trackTiming(action.endpoint.name, performance.now() - start); + action.meta.promise.then(track, track); + + // After + action.meta.promise + .finally(() => { + trackTiming(action.endpoint.name, performance.now() - start); + }) + // the fetch's caller handles errors; this only observes timing + .catch(() => {}); + ``` + +- [#4250](https://github.com/reactive/data-client/pull/4250) [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a) - Fixture `args` accept readonly tuples + + Fixtures written with `args: [...] as const` now type-check when passed to [MockResolver](https://dataclient.io/docs/api/MockResolver), `renderDataHook()`, Vue's `renderDataCompose()` or `mockInitialState()`. Before, TypeScript rejected them with "The type 'readonly [...]' is 'readonly' and cannot be assigned to the mutable type", so you had to drop `as const` or cast. + + ```ts + const fixtures = [ + { + endpoint: TodoResource.getList, + args: [{ userId: 1 }] as const, + response: [{ id: 1, title: 'Write tests', userId: 1 }], + }, + ]; + + // Before: type error on `fixtures`. After: works as written + + + ; + ``` + +- [#4232](https://github.com/reactive/data-client/pull/4232) [`31b1820`](https://github.com/reactive/data-client/commit/31b182033106d5ce44352481577d3c321e39ebe9) - Fix `',' expected` errors on TypeScript 4.0 through 4.4 + + Importing `@data-client/react/redux`, `@data-client/react/nextjs` or `@data-client/test` failed to compile on TypeScript before 4.5, even with `skipLibCheck` on, because their declaration files used syntax those versions can't parse. They now compile on TypeScript 4.0 and later. + + ```ts + import { DataProvider } from '@data-client/react/nextjs'; + import { renderDataHook } from '@data-client/test'; + + // Before (TypeScript 4.0 to 4.4): + // node_modules/@data-client/react/lib/server/nextjs/DataProvider/DataProvider.d.ts(1,15): error TS1005: ',' expected. + // node_modules/@data-client/test/lib/makeRenderDataClient/index.d.ts(3,33): error TS1005: ',' expected. + // After: no errors + ``` + + `@data-client/vue/test` types now also resolve with `moduleResolution: "node"`. + +- [#4122](https://github.com/reactive/data-client/pull/4122) [`b4b502d`](https://github.com/reactive/data-client/commit/b4b502d545aab0cf75bf030f3de4607a2e3ab7dc) - Fix types for TypeScript 4.x when `skipLibCheck` is off + + TypeScript 4.0 through 4.7 no longer report `Cannot find name 'NoInfer'` from `@data-client/endpoint` or `@data-client/normalizr`, and TypeScript 4.0 through 4.9 no longer report `Only named exports may use 'export type'` from `@data-client/normalizr`. + + ```ts + import { Entity } from '@data-client/endpoint'; + import { normalize } from '@data-client/normalizr'; + + // Before (TypeScript 4.7, skipLibCheck: false): + // error TS2304: Cannot find name 'NoInfer'. + // error TS1383: Only named exports may use 'export type'. + // After: no errors + ``` + +- [#4019](https://github.com/reactive/data-client/pull/4019) [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e) Thanks [@renovate](https://github.com/apps/renovate)! - Fix TypeScript 7 module resolution for package exports + + TypeScript 7 requires a `types` condition in `package.json` `exports`. Without it, imports resolved to runtime entrypoints like `node.mjs` and lost declaration files. + +- [#4193](https://github.com/reactive/data-client/pull/4193) [`3e45adc`](https://github.com/reactive/data-client/commit/3e45adc831ead1923f0590d8b6ee316655610d69) - `createDataClient()` and `ProvidedDataClient` are deprecated + + They only exist to implement [DataClientPlugin](https://dataclient.io/vue/api/DataClientPlugin) and will stop being + exported in a future release. Nothing changes at runtime. If you call `createDataClient()` directly, install the + plugin instead and read the controller with [useController()](https://dataclient.io/vue/api/useController). + + ```ts title="main.ts" + import { DataClientPlugin } from '@data-client/vue'; + + app.use(DataClientPlugin, { managers, initialState }); + ``` + +- [#4148](https://github.com/reactive/data-client/pull/4148) [`c5e95d4`](https://github.com/reactive/data-client/commit/c5e95d46a8d68ef04ccbcdc7bf90f663357a8530) - `DataClientPlugin` garbage collects by default + + Previously, unused data was only removed from the store if you passed a `gcPolicy` yourself. It now defaults + to `new GCPolicy()`, matching `DataProvider` in `@data-client/react`, so you can drop the option unless you + customize it. + + Before + + ```ts + import { DataClientPlugin, GCPolicy } from '@data-client/vue'; + + app.use(DataClientPlugin, { gcPolicy: new GCPolicy() }); + ``` + + After + + ```ts + import { DataClientPlugin } from '@data-client/vue'; + + app.use(DataClientPlugin); + ``` + +- [#4221](https://github.com/reactive/data-client/pull/4221) [`76a50c8`](https://github.com/reactive/data-client/commit/76a50c853d863140122cecbeb141fb278853849d) - `waitForNextUpdate()` from `renderDataCompose()` is deprecated + + It gives up silently after 1 second, so a test could pass while the composable was still suspended. When the Promise + had already resolved, it waited the full second for nothing, and under `jest.useFakeTimers()` it could hang. Await the + result directly instead, and use `allSettled()` after changing props or calling the controller. + + `allSettled()` from `renderDataCompose()` and `mountDataClient()` now also waits for fetches that a prop change starts, + and for the component to re-render, so you no longer need `nextTick()` around it. It also waits on a `NetworkManager` + you pass in `managers`, instead of returning right away. + + #### Before + + ```ts + import { reactive } from 'vue'; + + const props = reactive({ id: 5 }); + const { result, waitForNextUpdate } = await renderDataCompose( + (props: { id: number }) => + useSuspense(ArticleResource.get, () => ({ id: props.id })), + { props, resolverFixtures }, + ); + await waitForNextUpdate(); + const article = await result; + + props.id = 6; + await waitForNextUpdate(); + ``` + + #### After + + ```ts + import { reactive } from 'vue'; + + const props = reactive({ id: 5 }); + const { result, allSettled } = await renderDataCompose( + (props: { id: number }) => + useSuspense(ArticleResource.get, () => ({ id: props.id })), + { props, resolverFixtures }, + ); + const article = await result; + + props.id = 6; + await allSettled(); + ``` + +- [#4142](https://github.com/reactive/data-client/pull/4142) [`f5cc51b`](https://github.com/reactive/data-client/commit/f5cc51b2f77230f64ab24d91eca0072521a24ded) - Fix `useDLE()` and `useCache()` dropping expired `invalidIfStale` data on unrelated store updates + + After an `invalidIfStale` response expired, any unrelated store update switched these composables to empty data, and + `useDLE()` stayed `loading` without starting a fetch. Expiry is now only re-checked when the response's expiry, the + arguments, or a reset changes, matching `@data-client/react`. + + The `vue` peer dependency is now `^3.4.0`. + + ```ts + const { data, loading } = useDLE(ArticleResource.get, { id: 5 }); + // ...after the response's dataExpiryLength passes + await ctrl.setResponse(UserResource.get, { id: 1 }, user); + // Before: loading.value === true, data.value === undefined, and no fetch starts + // After: loading.value === false, data.value is still the article + ``` + +- [#4143](https://github.com/reactive/data-client/pull/4143) [`743d8e3`](https://github.com/reactive/data-client/commit/743d8e3dcc5e69a0725616a3ffe2568dee5727e9) - Export `GCPolicy` from `@data-client/vue` + + ```ts + // Before + import { GCPolicy } from '@data-client/core'; + // After + import { GCPolicy } from '@data-client/vue'; + + app.use(DataClientPlugin, { + gcPolicy: new GCPolicy({ intervalMS: 60 * 1000 * 10 }), + }); + ``` + +- [#4115](https://github.com/reactive/data-client/pull/4115) [`e350950`](https://github.com/reactive/data-client/commit/e35095045ade70f8151202b357beef2a38ff8272) - Fix getter function arguments in Vue composables + + `useSuspense`, `useLive`, `useCache`, `useDLE`, `useFetch`, `useQuery` and `useSubscription` + were typed to accept getter functions as arguments, but only resolved refs at runtime. Getters + now work and are tracked reactively, just like refs and `computed`. + + ```ts + const props = defineProps<{ id: number }>(); + + // Before: getter was passed to the endpoint as-is + // After: re-fetches when props.id changes + const article = await useSuspense(ArticleResource.get, () => ({ + id: props.id, + })); + ``` + +- [#4146](https://github.com/reactive/data-client/pull/4146) [`a8da8c7`](https://github.com/reactive/data-client/commit/a8da8c725de0097aff8fa9bab2f0db8ccfe7047c) - Fix `app.use(DataClientPlugin)` throwing `app.onUnmount is not a function` on Vue versions before 3.5 + + ```ts + const app = createApp(App); + // Before (Vue < 3.5): TypeError: app.onUnmount is not a function + // After: installs, and stops the DataClient when the app unmounts + app.use(DataClientPlugin); + ``` + +- [#4134](https://github.com/reactive/data-client/pull/4134) [`bd419cd`](https://github.com/reactive/data-client/commit/bd419cde7897f240440475adf942c64e6418307c) - Fix `useSuspense()`, `useDLE()` and `useFetch()` refetching stale data on every store update + + Once data was stale, any store update (such as `controller.set()`) made these composables refetch, so the server + response could overwrite the change. They now only refetch when the data's expiry, the arguments, or a reset changes, + matching `@data-client/react`. + + ```ts + const article = await useSuspense(ArticleResource.get, { id: 5 }); + // ...after the response's dataExpiryLength passes + await ctrl.set(Article, { id: 5 }, { id: 5, title: 'edited' }); + // Before: triggers a refetch that reverts title to the server value + // After: title stays 'edited' + ``` + +- [#4135](https://github.com/reactive/data-client/pull/4135) [`f03332e`](https://github.com/reactive/data-client/commit/f03332ea9a4e3b24dc1554cb3a4ff2ebc1b117ad) - Fix `useSuspense()` and `useLive()` fetch errors after arguments change being unhandled + + When ref or computed arguments changed and the new fetch failed, the error became an unhandled promise rejection + and the result became `undefined`. Reading the result now throws the error, like the first load does, so it reaches + `onErrorCaptured()`. + + ```ts + const props = defineProps<{ id: number }>(); + const todo = await useSuspense( + TodoResource.get, + computed(() => ({ id: props.id })), + ); + // Before: a failed fetch for a new id was an unhandled rejection; todo.value became undefined + // After: reading todo.value throws the fetch error, caught by onErrorCaptured() + ``` + +- [#4131](https://github.com/reactive/data-client/pull/4131) [`84b6766`](https://github.com/reactive/data-client/commit/84b67665f547bd52e7dc207af9ba768821041fac) - Fix `useSuspense()` and `useLive()` returning `undefined` while new arguments load + + When ref or computed arguments changed to data not yet in the store, the result became `undefined` until the + new fetch resolved, crashing templates like `{{ todo.title }}`. It now keeps the previous data until the new data arrives. + + ```ts + const props = defineProps<{ id: number }>(); + const todo = await useSuspense( + TodoResource.get, + computed(() => ({ id: props.id })), + ); + // Before: todo.value was undefined while the new id loaded + // After: todo.value keeps the previous todo until the new one arrives + ``` + +- [#4169](https://github.com/reactive/data-client/pull/4169) [`341e17c`](https://github.com/reactive/data-client/commit/341e17c087105b7cccd1609ad3df2cb15e10f1dc) - Fix Vue `useSuspense()` suspending on stale data instead of showing it while it refetches + + When a component mounted with cached data that was past its `dataExpiryLength` but still valid, `await useSuspense()` + waited for the refetch, so users saw the `` fallback instead of the data already on hand. Now, like React, + it renders the stale data right away and updates once the refetch resolves. Data that is missing, invalidated, or + [invalidIfStale](https://dataclient.io/rest/api/Endpoint#invalidifstale) still waits for the fetch. + +- [#4150](https://github.com/reactive/data-client/pull/4150) [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2) - Vue `useFetch()` keeps its response from being garbage collected while mounted, like React `useFetch()` and Vue `useSuspense()` + +- [#4114](https://github.com/reactive/data-client/pull/4114) [`7c24b70`](https://github.com/reactive/data-client/commit/7c24b706360208e167aff5d576ad679f7e8e2138) - Fix [useFetch()](https://dataclient.io/docs/api/useFetch) return type to be a read-only `Ref` + + `useFetch()` returns a read-only `Ref` holding the fetch promise, but was typed as returning the promise directly. + + ```ts + const promise = useFetch(PostResource.get, { id }); + // Before: promise.resolved typechecked, but was always undefined at runtime + // After: + if (!promise.value.resolved) { + // fetch is in-flight + } + ``` + +- Updated dependencies [[`f343f9d`](https://github.com/reactive/data-client/commit/f343f9d42a12f3ad763fac96362166d3b3156b69), [`46f1f24`](https://github.com/reactive/data-client/commit/46f1f24bcb04824805747ed2a1effe7baece337c), [`a82758c`](https://github.com/reactive/data-client/commit/a82758cd1998e58d7ad280407db28bd84f5d7b18), [`b55696c`](https://github.com/reactive/data-client/commit/b55696c72ad3e73e0a2f50d3751c7104cd4ad9ee), [`74e67fa`](https://github.com/reactive/data-client/commit/74e67fa2c4f9f104f5b7a49e877a48e5963e4bd2), [`159c963`](https://github.com/reactive/data-client/commit/159c9633679d95427fe4f626aec341c76e4578f8), [`4549122`](https://github.com/reactive/data-client/commit/4549122004244990a564781a61145ae9ea98370e), [`47502c6`](https://github.com/reactive/data-client/commit/47502c664df913297fba3e5011a975dfd01c0d8d), [`fc4b015`](https://github.com/reactive/data-client/commit/fc4b015ca0899a2685af881d17f765dce27ffc1a), [`aa15f29`](https://github.com/reactive/data-client/commit/aa15f29f6b0a3b4ae655e2d114a419a3fc94ac7e)]: + - @data-client/core@1.0.0 + ## 0.18.1 ### Patch Changes diff --git a/packages/vue/package.json b/packages/vue/package.json index d3b725922c33..16df03ae95f9 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "@data-client/vue", - "version": "0.18.1", + "version": "1.0.0", "description": "Async State Management without the Management. REST, GraphQL, SSE, Websockets, Fetch", "homepage": "https://dataclient.io", "repository": { diff --git a/yarn.lock b/yarn.lock index fe0b1bc6662e..5eb7316b486a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3234,7 +3234,7 @@ __metadata: languageName: unknown linkType: soft -"@data-client/img@npm:0.18.0, @data-client/img@workspace:*, @data-client/img@workspace:packages/img": +"@data-client/img@npm:1.0.0, @data-client/img@workspace:*, @data-client/img@workspace:packages/img": version: 0.0.0-use.local resolution: "@data-client/img@workspace:packages/img" dependencies: @@ -3252,7 +3252,7 @@ __metadata: react-dom: "npm:^19.2.1" rollup-plugins: "workspace:*" peerDependencies: - "@data-client/react": ^0.1.0 || ^0.2.0 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0 + "@data-client/react": ^1.0.0 "@types/react": ^16.14.0 || ^17.0.0 || ^18.0.0-0 || ^19.0.0 react: ^16.14.0 || ^17.0.0 || ^18.0.0-0 || ^19.0.0 peerDependenciesMeta: @@ -3276,7 +3276,7 @@ __metadata: languageName: unknown linkType: soft -"@data-client/react@npm:0.18.1, @data-client/react@workspace:*, @data-client/react@workspace:packages/react": +"@data-client/react@npm:1.0.0, @data-client/react@workspace:*, @data-client/react@workspace:packages/react": version: 0.0.0-use.local resolution: "@data-client/react@workspace:packages/react" dependencies: @@ -3322,7 +3322,7 @@ __metadata: languageName: unknown linkType: soft -"@data-client/rest@npm:0.18.1, @data-client/rest@workspace:*, @data-client/rest@workspace:packages/rest": +"@data-client/rest@npm:1.0.0, @data-client/rest@workspace:*, @data-client/rest@workspace:packages/rest": version: 0.0.0-use.local resolution: "@data-client/rest@workspace:packages/rest" dependencies: @@ -3361,7 +3361,7 @@ __metadata: react-test-renderer: "npm:*" rollup-plugins: "workspace:*" peerDependencies: - "@data-client/react": ^0.12.15 || ^0.13.0 || ^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0 + "@data-client/react": ^1.0.0 "@testing-library/react-hooks": ^8.0.0 "@testing-library/react-native": ^13.0.0 "@types/react": ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-0 || ^19.0.0 @@ -11606,9 +11606,9 @@ __metadata: "@anansi/webpack-config": "npm:21.1.19" "@babel/core": "npm:7.29.7" "@babel/runtime-corejs3": "npm:7.29.7" - "@data-client/img": "npm:0.18.0" - "@data-client/react": "npm:0.18.1" - "@data-client/rest": "npm:0.18.1" + "@data-client/img": "npm:1.0.0" + "@data-client/react": "npm:1.0.0" + "@data-client/rest": "npm:1.0.0" "@linaria/core": "npm:*" "@linaria/react": "npm:*" "@linaria/shaker": "npm:*"