diff --git a/README.md b/README.md index 37ec4edc944..1b42c6d98c5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![CircleCI](https://circleci.com/gh/coinbase/rest-hooks.svg?style=shield)](https://circleci.com/gh/coinbase/rest-hooks) [![Coverage Status](https://img.shields.io/coveralls/coinbase/rest-hooks.svg?style=flat-square)](https://coveralls.io/github/coinbase/rest-hooks?branch=master) [![npm downloads](https://img.shields.io/npm/dm/rest-hooks.svg?style=flat-square)](https://www.npmjs.com/package/rest-hooks) -[![bundle size](https://img.shields.io/bundlephobia/minzip/rest-hooks?style=flat-square)](https://bundlephobia.com/result?p=rest-hooks) +[![bundle size](https://img.shields.io/bundlephobia/minzip/@rest-hooks/core?style=flat-square)](https://bundlephobia.com/result?p=@rest-hooks/core) [![npm version](https://img.shields.io/npm/v/rest-hooks.svg?style=flat-square)](https://www.npmjs.com/package/rest-hooks) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) diff --git a/__tests__/common.ts b/__tests__/common.ts index d0967ff60e6..20a443b0a04 100644 --- a/__tests__/common.ts +++ b/__tests__/common.ts @@ -6,7 +6,11 @@ import { SchemaDetail, DeleteShape, } from 'rest-hooks'; -import { AbstractInstanceType, FetchOptions, MutateShape } from 'rest-hooks'; +import type { + AbstractInstanceType, + FetchOptions, + MutateShape, +} from '@rest-hooks/core'; import React from 'react'; export class UserResource extends Resource { diff --git a/__tests__/tsconfig.json b/__tests__/tsconfig.json index 56aee104a18..0344bc3ab32 100644 --- a/__tests__/tsconfig.json +++ b/__tests__/tsconfig.json @@ -5,6 +5,7 @@ }, "include": ["."], "references": [ + { "path": "../packages/core" }, { "path": "../packages/rest-hooks" } ] } diff --git a/jest.config.js b/jest.config.js index f2715a57c79..679a42f118e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -48,7 +48,13 @@ const baseConfig = { setupFiles: ['/scripts/testSetup.js'], }; -const packages = ['legacy', 'rest-hooks', 'normalizr', 'use-enhanced-reducer']; +const packages = [ + 'legacy', + 'core', + 'rest-hooks', + 'normalizr', + 'use-enhanced-reducer', +]; const projects = [ { diff --git a/packages/core/.gitignore b/packages/core/.gitignore new file mode 100644 index 00000000000..13d357aaf05 --- /dev/null +++ b/packages/core/.gitignore @@ -0,0 +1,2 @@ +/lib +/dist diff --git a/packages/core/LICENSE b/packages/core/LICENSE new file mode 100644 index 00000000000..61e840f5393 --- /dev/null +++ b/packages/core/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Coinbase, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/core/README.md b/packages/core/README.md new file mode 100644 index 00000000000..46e22bdad0b --- /dev/null +++ b/packages/core/README.md @@ -0,0 +1,83 @@ +# ![๐Ÿ›Œ๐ŸŽฃ Rest hooks](/packages/rest-hooks/rest_hooks_logo_and_text.svg?sanitize=true) +[![CircleCI](https://circleci.com/gh/coinbase/rest-hooks.svg?style=shield)](https://circleci.com/gh/coinbase/rest-hooks) +[![Coverage Status](https://img.shields.io/coveralls/coinbase/rest-hooks.svg?style=flat-square)](https://coveralls.io/github/coinbase/rest-hooks?branch=master) +[![npm downloads](https://img.shields.io/npm/dm/@rest-hooks/core.svg?style=flat-square)](https://www.npmjs.com/package/@rest-hooks/core) +[![bundle size](https://img.shields.io/bundlephobia/minzip/@rest-hooks/core?style=flat-square)](https://bundlephobia.com/result?p=@rest-hooks/core) +[![npm version](https://img.shields.io/npm/v/@rest-hooks/core.svg?style=flat-square)](https://www.npmjs.com/package/@rest-hooks/core) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) + +Making dynamic sites performant, scalable, simple to build with any API design. + +
+ +**[๐Ÿ“–Read The Docs](https://resthooks.io)**  |  [๐ŸGetting Started](https://resthooks.io/docs/getting-started/installation)  |  +[๐ŸŽฎDemo](https://codesandbox.io/s/rest-hooks-hinux?fontsize=14&module=%2Fsrc%2Fpages%2FIssueList.tsx) + +
+ +### Simple TypeScript definition + +```typescript +class ArticleResource extends Resource { + readonly id: number | undefined = undefined; + readonly title: string = ''; + readonly body: string = ''; + + pk() { return this.id; } + static urlRoot = '/articles/'; +} +``` + +### One line data hookup + +```tsx +const article = useResource(ArticleResource.detailShape(), { id }); +return ( + <> +

{article.title}

+

{article.body}

+ +); +``` + +### Mutation + +```tsx +const update = useFetcher(ArticleResource.updateShape()); +return update({ id }, data)} />; +``` + +### And subscriptions + +```tsx +const price = useResource(PriceResource.detailShape(), { symbol }); +useSubscription(PriceResource.detailShape(), { symbol });+ +return price.value; +``` + +### ...all typed ...fast ...and consistent + +For the small price of 7kb gziped.    [๐ŸGet started now](https://resthooks.io/docs/getting-started/installation) + +## Features + +- [x] ![TS](./typescript.svg?sanitize=true) Strong [Typescript](https://www.typescriptlang.org/) types +- [x] ๐Ÿ›Œ React [Suspense](https://resthooks.io/docs/guides/loading-state) support +- [x] โ›“๏ธ React [Concurrent mode](https://reactjs.org/docs/concurrent-mode-patterns.html) compatible +- [x] ๐ŸŽฃ Simple declarative API +- [x] ๐Ÿ’ฐ Normalized response [configurable](https://resthooks.io/docs/guides/resource-lifetime) caching +- [x] ๐Ÿ’ฅ Tiny bundle footprint +- [x] ๐Ÿ›‘ Automatic overfetching elimination +- [x] โœจ Optimistic updates +- [x] ๐Ÿง˜ [Flexible](https://resthooks.io/docs/api/FetchShape) to fit any API design (one size fits all) +- [x] ๐ŸŒณ Tree-shakable (only use what you need) +- [x] ๐Ÿ” [Subscriptions](https://resthooks.io/docs/api/useSubscription) +- [x] โ™ป๏ธ Optional [redux integration](https://resthooks.io/docs/guides/redux) +- [x] ๐Ÿ“™ [Storybook mocking](https://resthooks.io/docs/guides/storybook) +- [x] ๐Ÿ“ฑ [React Native](https://facebook.github.io/react-native/) support +- [ ] ๐Ÿšฏ Pluggable garbage collection policy + +### Special thanks + +Thanks to [@0xcaff](https://github.com/0xcaff), [@melissafzhang](https://github.com/melissafzhang) +and [@alexiswolfish](https://github.com/alexiswolfish) for their valuable feedback. diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 00000000000..9b9ce86e495 --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,78 @@ +{ + "name": "@rest-hooks/core", + "version": "1.0.0-beta.0", + "description": "Dynamic data fetching for React", + "sideEffects": false, + "main": "dist/index.cjs.js", + "module": "lib/index.js", + "unpkg": "dist/index.umd.min.js", + "types": "lib/index.d.ts", + "files": [ + "src", + "dist", + "lib", + "LICENSE", + "README.md", + "./typescript.svg", + "./rest_hooks_logo_and_text.svg" + ], + "scripts": { + "build:lib": "cross-env NODE_ENV=production ROOT_PATH_PREFIX='@rest-hooks/core' babel --root-mode upward src --out-dir lib --source-maps inline --extensions '.ts,.tsx,.js' --ignore '**/__tests__/**' --ignore '**/*.d.ts'", + "build:bundle": "rollup -c", + "build:clean": "rimraf lib dist *.tsbuildinfo", + "build": "yarn run build:lib && yarn run build:bundle", + "dev": "yarn run build:lib -w", + "prepare": "yarn run build:lib", + "prepublishOnly": "yarn run build:bundle", + "test": "cross-env NODE_ENV=test jest", + "test:ci": "yarn test -- --ci", + "test:watch": "yarn test -- --watch", + "test:coverage": "yarn test -- --coverage" + }, + "keywords": [ + "react", + "flux", + "ajax", + "networking", + "suspense", + "concurrent mode", + "fetch", + "hook", + "typescript", + "data fetching", + "data cache", + "api", + "api call", + "normalized cache", + "swr" + ], + "author": "Nathaniel Tucker (https://github.com/ntucker)", + "license": "Apache-2.0", + "homepage": "https://resthooks.io", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com:coinbase/rest-hooks.git", + "directory": "packages/core" + }, + "bugs": { + "url": "https://github.com/coinbase/rest-hooks/issues" + }, + "devDependencies": { + "@rest-hooks/test": "^2.0.0-beta.0" + }, + "dependencies": { + "@babel/runtime": "^7.7.2", + "@rest-hooks/normalizr": "^6.0.0-beta.1", + "@rest-hooks/use-enhanced-reducer": "^1.0.3", + "flux-standard-action": "^2.1.1" + }, + "peerDependencies": { + "@types/react": "^16.8.4", + "react": "^16.8.4" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } +} diff --git a/packages/core/rest_hooks_logo_and_text.svg b/packages/core/rest_hooks_logo_and_text.svg new file mode 100644 index 00000000000..40f03febe82 --- /dev/null +++ b/packages/core/rest_hooks_logo_and_text.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/core/rollup.config.js b/packages/core/rollup.config.js new file mode 100644 index 00000000000..96db23e7774 --- /dev/null +++ b/packages/core/rollup.config.js @@ -0,0 +1,76 @@ +import commonjs from 'rollup-plugin-commonjs'; +import resolve from 'rollup-plugin-node-resolve'; +import babel from 'rollup-plugin-babel'; +import json from 'rollup-plugin-json'; +import { terser } from 'rollup-plugin-terser'; +import filesize from 'rollup-plugin-filesize'; +import replace from 'rollup-plugin-replace'; + +import pkg from './package.json'; + +const dependencies = Object.keys(pkg.dependencies) + .concat(Object.keys(pkg.peerDependencies)) + .filter( + dep => + ![ + '@rest-hooks/normalizr', + '@rest-hooks/use-enhanced-reducer', + '@babel/runtime', + ].includes(dep), + ); + +const extensions = ['.js', '.ts', '.tsx', '.mjs', '.json', '.node']; +const nativeExtensions = ['.native.ts', ...extensions]; +process.env.NODE_ENV = 'production'; +process.env.BROWSERSLIST_ENV = 'legacy'; +process.env.ROOT_PATH_PREFIX = '@rest-hooks/core'; + +function isExternal(id) { + const ret = dependencies.includes(id); + if (!ret) { + for (const dep of dependencies) { + if (id.startsWith(dep)) return true; + } + } + return ret; +} + +export default [ + // browser-friendly UMD build + { + input: 'src/index.ts', + external: isExternal, + output: [{ file: pkg.unpkg, format: 'umd', name: 'restHookCore' }], + plugins: [ + babel({ + exclude: ['node_modules/**', '/**__tests__/**'], + extensions, + rootMode: 'upward', + runtimeHelpers: true, + }), + replace({ 'process.env.NODE_ENV': JSON.stringify('production') }), + resolve({ extensions }), + commonjs({ extensions }), + json(), + terser({}), + filesize({ showBrotliSize: true }), + ], + }, + // node-friendly commonjs build + { + input: 'src/index.ts', + external: isExternal, + output: [{ file: pkg.main, format: 'cjs' }], + plugins: [ + babel({ + exclude: ['node_modules/**', '**/__tests__/**', '**/*.d.ts'], + extensions: nativeExtensions, + rootMode: 'upward', + runtimeHelpers: true, + }), + replace({ 'process.env.CJS': 'true' }), + resolve({ extensions: nativeExtensions }), + commonjs({ extensions: nativeExtensions }), + ], + }, +]; diff --git a/packages/rest-hooks/src/actionTypes.ts b/packages/core/src/actionTypes.ts similarity index 100% rename from packages/rest-hooks/src/actionTypes.ts rename to packages/core/src/actionTypes.ts diff --git a/packages/core/src/endpoint/index.ts b/packages/core/src/endpoint/index.ts new file mode 100644 index 00000000000..a45ecc42fd3 --- /dev/null +++ b/packages/core/src/endpoint/index.ts @@ -0,0 +1,16 @@ +export type { FetchShape, ReadShape, MutateShape, DeleteShape } from './shapes'; +export type { + SetShapeParams, + ParamsFromShape, + OptimisticUpdateParams, + SchemaFromShape, + BodyFromShape, +} from './types'; +export { isDeleteShape } from './types'; + +export type { + Normalize, + Denormalize, + DenormalizeNullable, + NormalizeNullable, +} from './normal'; diff --git a/packages/rest-hooks/src/resource/normal.ts b/packages/core/src/endpoint/normal.ts similarity index 82% rename from packages/rest-hooks/src/resource/normal.ts rename to packages/core/src/endpoint/normal.ts index ecd596bba39..de4d3a9a10d 100644 --- a/packages/rest-hooks/src/resource/normal.ts +++ b/packages/core/src/endpoint/normal.ts @@ -1,24 +1,10 @@ import { schema as schemas, - Schema, Denormalize as DenormalizeCore, DenormalizeNullable as DenormalizeNullableCore, Normalize as NormalizeCore, NormalizeNullable as NormalizeNullableCore, } from '@rest-hooks/normalizr'; -export * from '@rest-hooks/normalizr'; -export { schemas }; - -export type SchemaDetail = - | schemas.EntityInterface - | { [K: string]: any } - | schemas.SchemaClass; - -export type SchemaList = - | schemas.EntityInterface[] - | { [K: string]: any } - | Schema[] - | schemas.SchemaClass; export type Denormalize = Extract extends never ? Extract extends never diff --git a/packages/rest-hooks/src/resource/shapes.ts b/packages/core/src/endpoint/shapes.ts similarity index 92% rename from packages/rest-hooks/src/resource/shapes.ts rename to packages/core/src/endpoint/shapes.ts index d0e05d8df1b..cb701949493 100644 --- a/packages/rest-hooks/src/resource/shapes.ts +++ b/packages/core/src/endpoint/shapes.ts @@ -1,7 +1,5 @@ -import { FetchOptions } from 'rest-hooks/types'; -import { Entity } from '@rest-hooks/normalizr'; - -import { Schema } from './normal'; +import { FetchOptions } from '@rest-hooks/core/types'; +import { Entity, Schema } from '@rest-hooks/normalizr'; /** Defines the shape of a network request */ export interface FetchShape< diff --git a/packages/rest-hooks/src/resource/publicTypes.ts b/packages/core/src/endpoint/types.ts similarity index 66% rename from packages/rest-hooks/src/resource/publicTypes.ts rename to packages/core/src/endpoint/types.ts index 481038895e9..041d0359426 100644 --- a/packages/rest-hooks/src/resource/publicTypes.ts +++ b/packages/core/src/endpoint/types.ts @@ -1,7 +1,31 @@ -import { UpdateFunction } from 'rest-hooks/types'; +import { UpdateFunction } from '@rest-hooks/core/types'; import { Schema } from '@rest-hooks/normalizr'; -import { FetchShape } from './shapes'; +import { FetchShape, DeleteShape } from './shapes'; + +export function isDeleteShape( + shape: FetchShape, +): shape is DeleteShape { + return shape.type === 'delete'; +} + +export type ResultShape = RS extends { schema: infer U } ? U : never; +export type SelectReturn = RS extends { + select: (...args: any[]) => infer U; +} + ? U + : never; +export type AlwaysSelect = NonNullable>; +export type ParamArg = RS extends { + getFetchKey: (params: infer U) => any; +} + ? U + : never; +export type BodyArg = RS extends { + fetch: (url: any, body: infer U) => any; +} + ? U + : never; /** Sets a FetchShape's Param type. * Useful to constrain acceptable params (second arg) in hooks like useResource(). diff --git a/packages/rest-hooks/src/fsa.ts b/packages/core/src/fsa.ts similarity index 100% rename from packages/rest-hooks/src/fsa.ts rename to packages/core/src/fsa.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts new file mode 100644 index 00000000000..a90c4d29ca7 --- /dev/null +++ b/packages/core/src/index.ts @@ -0,0 +1,48 @@ +import buildInferredResults from './state/selectors/buildInferredResults'; +import RIC from './state/RIC'; + +const __INTERNAL__ = { + buildInferredResults, + RIC, +}; + +export { __INTERNAL__ }; +export { default as NetworkManager } from './state/NetworkManager'; +export { default as reducer, initialState } from './state/reducer'; +export { useDenormalized } from './state/selectors'; +export { + useCache, + useFetcher, + useRetrieve, + useResource, + useSubscription, + useMeta, + useError, + CacheProvider, + useInvalidator, + useResetter, + hasUsableData, +} from './react-integration'; +export { StateContext, DispatchContext } from './react-integration/context'; + +export { + SimpleRecord, + Entity as NestedEntity, + isEntity, + FlatEntity as Entity, + schema, +} from '@rest-hooks/normalizr'; +export type { Schema } from '@rest-hooks/normalizr'; + +export * from './state/actions'; +export * as actionTypes from './actionTypes'; +export * from '@rest-hooks/use-enhanced-reducer'; +/* istanbul ignore next */ +export * from './types'; +export type { + FetchShape, + ReadShape, + MutateShape, + DeleteShape, +} from './endpoint/shapes'; +export type { SetShapeParams, ParamsFromShape } from './endpoint/types'; diff --git a/packages/rest-hooks/src/react-integration/__tests__/__snapshots__/hooks.tsx.snap b/packages/core/src/react-integration/__tests__/__snapshots__/hooks.tsx.snap similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/__snapshots__/hooks.tsx.snap rename to packages/core/src/react-integration/__tests__/__snapshots__/hooks.tsx.snap diff --git a/packages/rest-hooks/src/react-integration/__tests__/__snapshots__/useCache.tsx.snap b/packages/core/src/react-integration/__tests__/__snapshots__/useCache.tsx.snap similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/__snapshots__/useCache.tsx.snap rename to packages/core/src/react-integration/__tests__/__snapshots__/useCache.tsx.snap diff --git a/packages/rest-hooks/src/react-integration/__tests__/__snapshots__/useResource.tsx.snap b/packages/core/src/react-integration/__tests__/__snapshots__/useResource.tsx.snap similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/__snapshots__/useResource.tsx.snap rename to packages/core/src/react-integration/__tests__/__snapshots__/useResource.tsx.snap diff --git a/packages/rest-hooks/src/react-integration/__tests__/fixtures.ts b/packages/core/src/react-integration/__tests__/fixtures.ts similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/fixtures.ts rename to packages/core/src/react-integration/__tests__/fixtures.ts diff --git a/packages/rest-hooks/src/react-integration/__tests__/hooks.tsx b/packages/core/src/react-integration/__tests__/hooks.tsx similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/hooks.tsx rename to packages/core/src/react-integration/__tests__/hooks.tsx diff --git a/packages/rest-hooks/src/react-integration/__tests__/integration.tsx b/packages/core/src/react-integration/__tests__/integration.tsx similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/integration.tsx rename to packages/core/src/react-integration/__tests__/integration.tsx diff --git a/packages/rest-hooks/src/react-integration/__tests__/subscriptions.tsx b/packages/core/src/react-integration/__tests__/subscriptions.tsx similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/subscriptions.tsx rename to packages/core/src/react-integration/__tests__/subscriptions.tsx diff --git a/packages/rest-hooks/src/react-integration/__tests__/useCache.tsx b/packages/core/src/react-integration/__tests__/useCache.tsx similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/useCache.tsx rename to packages/core/src/react-integration/__tests__/useCache.tsx diff --git a/packages/rest-hooks/src/react-integration/__tests__/useError.tsx b/packages/core/src/react-integration/__tests__/useError.tsx similarity index 100% rename from packages/rest-hooks/src/react-integration/__tests__/useError.tsx rename to packages/core/src/react-integration/__tests__/useError.tsx diff --git a/packages/rest-hooks/src/react-integration/__tests__/useResource.tsx b/packages/core/src/react-integration/__tests__/useResource.tsx similarity index 96% rename from packages/rest-hooks/src/react-integration/__tests__/useResource.tsx rename to packages/core/src/react-integration/__tests__/useResource.tsx index 467deba93eb..8af16a8065a 100644 --- a/packages/rest-hooks/src/react-integration/__tests__/useResource.tsx +++ b/packages/core/src/react-integration/__tests__/useResource.tsx @@ -4,20 +4,21 @@ import { InvalidIfStaleArticleResource, photoShape, } from '__tests__/common'; -import { State } from 'rest-hooks/types'; -import { initialState } from 'rest-hooks/state/reducer'; +import { State } from '@rest-hooks/core'; +import { initialState } from '@rest-hooks/core/state/reducer'; import React, { Suspense } from 'react'; import { render } from '@testing-library/react'; import nock from 'nock'; // relative imports to avoid circular dependency in tsconfig references +import { normalize } from '@rest-hooks/normalizr'; + import { makeRenderRestHook, makeCacheProvider, mockInitialState, } from '../../../../test'; -import { normalize } from '../../resource'; import { DispatchContext, StateContext } from '../context'; import { useResource } from '../hooks'; import { payload, users, nested } from './fixtures'; @@ -218,10 +219,7 @@ describe('useResource()', () => { expect(title.tagName).toBe('H3'); }); it('should NOT suspend even when result is stale and options.invalidIfStale is false', () => { - const { entities, result } = normalize( - payload, - CoolerArticleResource.getEntitySchema(), - ); + const { entities, result } = normalize(payload, CoolerArticleResource); const fetchKey = CoolerArticleResource.detailShape().getFetchKey(payload); const state = { ...initialState, @@ -255,7 +253,7 @@ describe('useResource()', () => { it('should NOT suspend if result is not stale and options.invalidIfStale is true', () => { const { entities, result } = normalize( payload, - InvalidIfStaleArticleResource.getEntitySchema(), + InvalidIfStaleArticleResource, ); const fetchKey = InvalidIfStaleArticleResource.detailShape().getFetchKey( payload, @@ -290,7 +288,7 @@ describe('useResource()', () => { it('should suspend if result stale in cache and options.invalidIfStale is true', () => { const { entities, result } = normalize( payload, - InvalidIfStaleArticleResource.getEntitySchema(), + InvalidIfStaleArticleResource, ); const fetchKey = InvalidIfStaleArticleResource.detailShape().getFetchKey( payload, diff --git a/packages/rest-hooks/src/react-integration/context.ts b/packages/core/src/react-integration/context.ts similarity index 85% rename from packages/rest-hooks/src/react-integration/context.ts rename to packages/core/src/react-integration/context.ts index 34b61001ef4..99b6050d003 100644 --- a/packages/rest-hooks/src/react-integration/context.ts +++ b/packages/core/src/react-integration/context.ts @@ -1,6 +1,6 @@ import { createContext } from 'react'; -import { ActionTypes } from 'rest-hooks/types'; -import { initialState } from 'rest-hooks/state/reducer'; +import { ActionTypes } from '@rest-hooks/core/types'; +import { initialState } from '@rest-hooks/core/state/reducer'; export const StateContext = createContext(initialState); diff --git a/packages/rest-hooks/src/react-integration/hooks/hasUsableData.ts b/packages/core/src/react-integration/hooks/hasUsableData.ts similarity index 83% rename from packages/rest-hooks/src/react-integration/hooks/hasUsableData.ts rename to packages/core/src/react-integration/hooks/hasUsableData.ts index 3982584c4e2..38e9da22728 100644 --- a/packages/rest-hooks/src/react-integration/hooks/hasUsableData.ts +++ b/packages/core/src/react-integration/hooks/hasUsableData.ts @@ -1,4 +1,4 @@ -import { FetchShape } from 'rest-hooks/resource'; +import { FetchShape } from '@rest-hooks/core/endpoint'; /** If the invalidIfStale option is set we suspend if resource has expired */ export default function hasUsableData( diff --git a/packages/rest-hooks/src/react-integration/hooks/index.ts b/packages/core/src/react-integration/hooks/index.ts similarity index 89% rename from packages/rest-hooks/src/react-integration/hooks/index.ts rename to packages/core/src/react-integration/hooks/index.ts index 16263cf52bf..3f869c43c06 100644 --- a/packages/rest-hooks/src/react-integration/hooks/index.ts +++ b/packages/core/src/react-integration/hooks/index.ts @@ -7,6 +7,7 @@ import useMeta from './useMeta'; import useError from './useError'; import useInvalidator from './useInvalidator'; import useResetter from './useResetter'; +export { default as hasUsableData } from './hasUsableData'; export { useFetcher, diff --git a/packages/rest-hooks/src/react-integration/hooks/useCache.ts b/packages/core/src/react-integration/hooks/useCache.ts similarity index 82% rename from packages/rest-hooks/src/react-integration/hooks/useCache.ts rename to packages/core/src/react-integration/hooks/useCache.ts index 447002755c5..698322137dd 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useCache.ts +++ b/packages/core/src/react-integration/hooks/useCache.ts @@ -1,7 +1,7 @@ -import { StateContext } from 'rest-hooks/react-integration/context'; -import { ReadShape, ParamsFromShape } from 'rest-hooks/resource'; -import { useDenormalized } from 'rest-hooks/state/selectors'; +import { ReadShape, ParamsFromShape } from '@rest-hooks/core/endpoint'; +import { useDenormalized } from '@rest-hooks/core/state/selectors'; import { useContext, useMemo } from 'react'; +import { StateContext } from '@rest-hooks/core/react-integration/context'; import useExpiresAt from './useExpiresAt'; diff --git a/packages/rest-hooks/src/react-integration/hooks/useError.ts b/packages/core/src/react-integration/hooks/useError.ts similarity index 88% rename from packages/rest-hooks/src/react-integration/hooks/useError.ts rename to packages/core/src/react-integration/hooks/useError.ts index c3f25f1a7e8..92159535132 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useError.ts +++ b/packages/core/src/react-integration/hooks/useError.ts @@ -1,4 +1,5 @@ -import { ReadShape, Schema } from 'rest-hooks/resource'; +import { ReadShape } from '@rest-hooks/core/endpoint'; +import { Schema } from '@rest-hooks/normalizr'; import useMeta from './useMeta'; diff --git a/packages/rest-hooks/src/react-integration/hooks/useExpiresAt.ts b/packages/core/src/react-integration/hooks/useExpiresAt.ts similarity index 86% rename from packages/rest-hooks/src/react-integration/hooks/useExpiresAt.ts rename to packages/core/src/react-integration/hooks/useExpiresAt.ts index 6d076121a22..f46caebdc0e 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useExpiresAt.ts +++ b/packages/core/src/react-integration/hooks/useExpiresAt.ts @@ -1,4 +1,4 @@ -import { ReadShape } from 'rest-hooks/resource'; +import { ReadShape } from '@rest-hooks/core/endpoint'; import useMeta from './useMeta'; diff --git a/packages/rest-hooks/src/react-integration/hooks/useFetcher.ts b/packages/core/src/react-integration/hooks/useFetcher.ts similarity index 88% rename from packages/rest-hooks/src/react-integration/hooks/useFetcher.ts rename to packages/core/src/react-integration/hooks/useFetcher.ts index 29ea4c62bf7..8af16cc9460 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useFetcher.ts +++ b/packages/core/src/react-integration/hooks/useFetcher.ts @@ -1,14 +1,14 @@ import { FetchShape, DeleteShape, - Schema, SchemaFromShape, ParamsFromShape, BodyFromShape, OptimisticUpdateParams, -} from 'rest-hooks/resource'; -import { DispatchContext } from 'rest-hooks/react-integration/context'; -import createFetch from 'rest-hooks/state/actions/createFetch'; +} from '@rest-hooks/core/endpoint'; +import { Schema } from '@rest-hooks/normalizr'; +import { DispatchContext } from '@rest-hooks/core/react-integration/context'; +import createFetch from '@rest-hooks/core/state/actions/createFetch'; import { useContext, useRef, useCallback } from 'react'; /** Build an imperative dispatcher to issue network requests. */ diff --git a/packages/rest-hooks/src/react-integration/hooks/useInvalidator.ts b/packages/core/src/react-integration/hooks/useInvalidator.ts similarity index 74% rename from packages/rest-hooks/src/react-integration/hooks/useInvalidator.ts rename to packages/core/src/react-integration/hooks/useInvalidator.ts index 1a7ba2a0934..f21332f9b74 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useInvalidator.ts +++ b/packages/core/src/react-integration/hooks/useInvalidator.ts @@ -1,7 +1,8 @@ import { useContext, useCallback, useRef } from 'react'; -import { ReadShape, Schema } from 'rest-hooks/resource'; -import { DispatchContext } from 'rest-hooks/react-integration/context'; -import { INVALIDATE_TYPE } from 'rest-hooks/actionTypes'; +import { ReadShape } from '@rest-hooks/core/endpoint'; +import { Schema } from '@rest-hooks/normalizr'; +import { DispatchContext } from '@rest-hooks/core/react-integration/context'; +import { INVALIDATE_TYPE } from '@rest-hooks/core/actionTypes'; /** Invalidate a certain item within the cache */ export default function useInvalidator< diff --git a/packages/rest-hooks/src/react-integration/hooks/useMeta.ts b/packages/core/src/react-integration/hooks/useMeta.ts similarity index 69% rename from packages/rest-hooks/src/react-integration/hooks/useMeta.ts rename to packages/core/src/react-integration/hooks/useMeta.ts index 985bfc8edde..a736d2b0140 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useMeta.ts +++ b/packages/core/src/react-integration/hooks/useMeta.ts @@ -1,6 +1,6 @@ -import { FetchShape } from 'rest-hooks/resource'; -import { StateContext } from 'rest-hooks/react-integration/context'; -import { selectMeta } from 'rest-hooks/state/selectors'; +import { FetchShape } from '@rest-hooks/core/endpoint'; +import { StateContext } from '@rest-hooks/core/react-integration/context'; +import { selectMeta } from '@rest-hooks/core/state/selectors'; import { useContext, useMemo } from 'react'; /** Gets meta for a fetch key. */ diff --git a/packages/rest-hooks/src/react-integration/hooks/useResetter.ts b/packages/core/src/react-integration/hooks/useResetter.ts similarity index 72% rename from packages/rest-hooks/src/react-integration/hooks/useResetter.ts rename to packages/core/src/react-integration/hooks/useResetter.ts index 2cacffda858..2b0bfc22ec4 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useResetter.ts +++ b/packages/core/src/react-integration/hooks/useResetter.ts @@ -1,5 +1,5 @@ -import { DispatchContext } from 'rest-hooks/react-integration/context'; -import { RESET_TYPE } from 'rest-hooks/actionTypes'; +import { DispatchContext } from '@rest-hooks/core/react-integration/context'; +import { RESET_TYPE } from '@rest-hooks/core/actionTypes'; import { useContext, useCallback } from 'react'; /** Returns a function to completely clear the cache of all entries */ diff --git a/packages/rest-hooks/src/react-integration/hooks/useResource.ts b/packages/core/src/react-integration/hooks/useResource.ts similarity index 99% rename from packages/rest-hooks/src/react-integration/hooks/useResource.ts rename to packages/core/src/react-integration/hooks/useResource.ts index c7b0a03d3a8..27d4db7c944 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useResource.ts +++ b/packages/core/src/react-integration/hooks/useResource.ts @@ -3,9 +3,9 @@ import { Denormalize, DenormalizeNullable, ParamsFromShape, -} from 'rest-hooks/resource'; -import { useDenormalized } from 'rest-hooks/state/selectors'; -import { StateContext } from 'rest-hooks/react-integration/context'; +} from '@rest-hooks/core/endpoint'; +import { useDenormalized } from '@rest-hooks/core/state/selectors'; +import { StateContext } from '@rest-hooks/core/react-integration/context'; import { useMemo, useContext } from 'react'; import useRetrieve from './useRetrieve'; diff --git a/packages/rest-hooks/src/react-integration/hooks/useRetrieve.ts b/packages/core/src/react-integration/hooks/useRetrieve.ts similarity index 91% rename from packages/rest-hooks/src/react-integration/hooks/useRetrieve.ts rename to packages/core/src/react-integration/hooks/useRetrieve.ts index 701e5af77d1..a1a49e231a9 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useRetrieve.ts +++ b/packages/core/src/react-integration/hooks/useRetrieve.ts @@ -1,4 +1,4 @@ -import { ReadShape, ParamsFromShape } from 'rest-hooks/resource'; +import { ReadShape, ParamsFromShape } from '@rest-hooks/core/endpoint'; import { useMemo } from 'react'; import useFetcher from './useFetcher'; diff --git a/packages/rest-hooks/src/react-integration/hooks/useSubscription.ts b/packages/core/src/react-integration/hooks/useSubscription.ts similarity index 84% rename from packages/rest-hooks/src/react-integration/hooks/useSubscription.ts rename to packages/core/src/react-integration/hooks/useSubscription.ts index a2cc7f3a720..42767e54fc3 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useSubscription.ts +++ b/packages/core/src/react-integration/hooks/useSubscription.ts @@ -1,6 +1,7 @@ -import { DispatchContext } from 'rest-hooks/react-integration/context'; -import { ReadShape, Schema } from 'rest-hooks/resource'; -import { SUBSCRIBE_TYPE, UNSUBSCRIBE_TYPE } from 'rest-hooks/actionTypes'; +import { DispatchContext } from '@rest-hooks/core/react-integration/context'; +import { ReadShape } from '@rest-hooks/core/endpoint'; +import { Schema } from '@rest-hooks/normalizr'; +import { SUBSCRIBE_TYPE, UNSUBSCRIBE_TYPE } from '@rest-hooks/core/actionTypes'; import { useContext, useEffect, useRef } from 'react'; /** Keeps a resource fresh by subscribing to updates. */ diff --git a/packages/core/src/react-integration/index.ts b/packages/core/src/react-integration/index.ts new file mode 100644 index 00000000000..5c89ff5c2fe --- /dev/null +++ b/packages/core/src/react-integration/index.ts @@ -0,0 +1,2 @@ +export * from './provider'; +export * from './hooks'; diff --git a/packages/rest-hooks/src/react-integration/provider/CacheProvider.tsx b/packages/core/src/react-integration/provider/CacheProvider.tsx similarity index 71% rename from packages/rest-hooks/src/react-integration/provider/CacheProvider.tsx rename to packages/core/src/react-integration/provider/CacheProvider.tsx index 5d1c6f22abb..1e1cbe62d49 100644 --- a/packages/rest-hooks/src/react-integration/provider/CacheProvider.tsx +++ b/packages/core/src/react-integration/provider/CacheProvider.tsx @@ -1,17 +1,13 @@ -import { - StateContext, - DispatchContext, -} from 'rest-hooks/react-integration/context'; import masterReducer, { initialState as defaultState, -} from 'rest-hooks/state/reducer'; -import NetworkManager from 'rest-hooks/state/NetworkManager'; -import SubscriptionManager from 'rest-hooks/state/SubscriptionManager'; -import PollingSubscription from 'rest-hooks/state/PollingSubscription'; -import { State, Manager } from 'rest-hooks/types'; +} from '@rest-hooks/core/state/reducer'; +import NetworkManager from '@rest-hooks/core/state/NetworkManager'; +import { State, Manager } from '@rest-hooks/core/types'; import useEnhancedReducer from '@rest-hooks/use-enhanced-reducer'; import React, { ReactNode, useEffect, useMemo } from 'react'; +import { StateContext, DispatchContext } from '../context'; + interface ProviderProps { children: ReactNode; managers: Manager[]; @@ -54,9 +50,6 @@ export default function CacheProvider({ ); } CacheProvider.defaultProps = { - managers: [ - new NetworkManager(), - new SubscriptionManager(PollingSubscription), - ], - initialState: defaultState, + managers: [new NetworkManager()] as Manager[], + initialState: defaultState as State, }; diff --git a/packages/rest-hooks/src/react-integration/provider/__tests__/__snapshots__/provider.tsx.snap b/packages/core/src/react-integration/provider/__tests__/__snapshots__/provider.tsx.snap similarity index 100% rename from packages/rest-hooks/src/react-integration/provider/__tests__/__snapshots__/provider.tsx.snap rename to packages/core/src/react-integration/provider/__tests__/__snapshots__/provider.tsx.snap diff --git a/packages/rest-hooks/src/react-integration/provider/__tests__/provider.tsx b/packages/core/src/react-integration/provider/__tests__/provider.tsx similarity index 82% rename from packages/rest-hooks/src/react-integration/provider/__tests__/provider.tsx rename to packages/core/src/react-integration/provider/__tests__/provider.tsx index fd6f6c5e55d..42acc1e83a6 100644 --- a/packages/rest-hooks/src/react-integration/provider/__tests__/provider.tsx +++ b/packages/core/src/react-integration/provider/__tests__/provider.tsx @@ -1,13 +1,10 @@ import { CoolerArticleResource } from '__tests__/common'; -import { RECEIVE_TYPE } from 'rest-hooks/actionTypes'; +import { RECEIVE_TYPE } from '@rest-hooks/core/actionTypes'; import React, { useContext } from 'react'; import { act, render } from '@testing-library/react'; import { DispatchContext, StateContext } from '../../context'; import CacheProvider from '../CacheProvider'; -import NetworkManager from '../../../state/NetworkManager'; -import SubscriptionManager from '../../../state/SubscriptionManager'; -import PollingSubscription from '../../../state/PollingSubscription'; describe('', () => { it('should not change dispatch function on re-render', () => { @@ -29,22 +26,19 @@ describe('', () => { rerender({chil}); expect(curDisp).toBe(dispatch); expect(count).toBe(1); - const managers = [ - new NetworkManager(), - new SubscriptionManager(PollingSubscription), - ]; + const managers: any[] = []; rerender({chil}); curDisp = dispatch; rerender({chil}); expect(curDisp).toBe(dispatch); - expect(count).toBe(2); + expect(count).toBe(1); rerender( Promise.resolve()}> {chil} , ); expect(curDisp).not.toBe(dispatch); - expect(count).toBe(3); + expect(count).toBe(2); }); it('should change state', () => { let dispatch: any, state; @@ -64,7 +58,7 @@ describe('', () => { type: RECEIVE_TYPE, payload: { id: 5, title: 'hi', content: 'more things here' }, meta: { - schema: CoolerArticleResource.getEntitySchema(), + schema: CoolerArticleResource, key: CoolerArticleResource.url({ id: 5 }), mutate: false, date: 50, diff --git a/packages/core/src/react-integration/provider/index.ts b/packages/core/src/react-integration/provider/index.ts new file mode 100644 index 00000000000..ea355dd9c16 --- /dev/null +++ b/packages/core/src/react-integration/provider/index.ts @@ -0,0 +1,3 @@ +import CacheProvider from './CacheProvider'; + +export { CacheProvider }; diff --git a/packages/rest-hooks/src/state/NetworkManager.ts b/packages/core/src/state/NetworkManager.ts similarity index 98% rename from packages/rest-hooks/src/state/NetworkManager.ts rename to packages/core/src/state/NetworkManager.ts index f3df398a633..5e5bf08a3f6 100644 --- a/packages/rest-hooks/src/state/NetworkManager.ts +++ b/packages/core/src/state/NetworkManager.ts @@ -3,13 +3,13 @@ import { Middleware, Dispatch, } from '@rest-hooks/use-enhanced-reducer'; -import { FetchAction, ReceiveAction, Manager } from 'rest-hooks/types'; +import { FetchAction, ReceiveAction, Manager } from '@rest-hooks/core/types'; import { RECEIVE_TYPE, RECEIVE_DELETE_TYPE, FETCH_TYPE, RESET_TYPE, -} from 'rest-hooks/actionTypes'; +} from '@rest-hooks/core/actionTypes'; import RIC from './RIC'; import { createReceive, createReceiveError } from './actions'; diff --git a/packages/rest-hooks/src/state/RIC.ts b/packages/core/src/state/RIC.ts similarity index 100% rename from packages/rest-hooks/src/state/RIC.ts rename to packages/core/src/state/RIC.ts diff --git a/packages/rest-hooks/src/state/__tests__/__snapshots__/reducer.ts.snap b/packages/core/src/state/__tests__/__snapshots__/reducer.ts.snap similarity index 100% rename from packages/rest-hooks/src/state/__tests__/__snapshots__/reducer.ts.snap rename to packages/core/src/state/__tests__/__snapshots__/reducer.ts.snap diff --git a/packages/rest-hooks/src/state/__tests__/applyUpdatersToResults.ts b/packages/core/src/state/__tests__/applyUpdatersToResults.ts similarity index 100% rename from packages/rest-hooks/src/state/__tests__/applyUpdatersToResults.ts rename to packages/core/src/state/__tests__/applyUpdatersToResults.ts diff --git a/packages/rest-hooks/src/state/__tests__/merge.tsx b/packages/core/src/state/__tests__/merge.tsx similarity index 100% rename from packages/rest-hooks/src/state/__tests__/merge.tsx rename to packages/core/src/state/__tests__/merge.tsx diff --git a/packages/rest-hooks/src/state/__tests__/networkManager.ts b/packages/core/src/state/__tests__/networkManager.ts similarity index 100% rename from packages/rest-hooks/src/state/__tests__/networkManager.ts rename to packages/core/src/state/__tests__/networkManager.ts diff --git a/packages/rest-hooks/src/state/__tests__/reducer.ts b/packages/core/src/state/__tests__/reducer.ts similarity index 100% rename from packages/rest-hooks/src/state/__tests__/reducer.ts rename to packages/core/src/state/__tests__/reducer.ts diff --git a/packages/rest-hooks/src/state/actions/createFetch.ts b/packages/core/src/state/actions/createFetch.ts similarity index 91% rename from packages/rest-hooks/src/state/actions/createFetch.ts rename to packages/core/src/state/actions/createFetch.ts index 43f0a9e1965..55bf0ca4af6 100644 --- a/packages/rest-hooks/src/state/actions/createFetch.ts +++ b/packages/core/src/state/actions/createFetch.ts @@ -1,14 +1,14 @@ -import { FetchAction } from 'rest-hooks/types'; -import { FETCH_TYPE } from 'rest-hooks/actionTypes'; +import { FetchAction } from '@rest-hooks/core/types'; +import { FETCH_TYPE } from '@rest-hooks/core/actionTypes'; +import { Schema } from '@rest-hooks/normalizr'; import { FetchShape, - Schema, isDeleteShape, SchemaFromShape, ParamsFromShape, BodyFromShape, OptimisticUpdateParams, -} from 'rest-hooks/resource'; +} from '@rest-hooks/core/endpoint'; interface Options< Shape extends FetchShape< diff --git a/packages/rest-hooks/src/state/actions/createReceive.ts b/packages/core/src/state/actions/createReceive.ts similarity index 94% rename from packages/rest-hooks/src/state/actions/createReceive.ts rename to packages/core/src/state/actions/createReceive.ts index 9fbc0823121..7d062d21422 100644 --- a/packages/rest-hooks/src/state/actions/createReceive.ts +++ b/packages/core/src/state/actions/createReceive.ts @@ -1,10 +1,10 @@ -import { Schema } from 'rest-hooks/resource'; +import { Schema } from '@rest-hooks/normalizr'; import { FetchAction, ReceiveAction, PurgeAction, FetchOptions, -} from 'rest-hooks/types'; +} from '@rest-hooks/core/types'; import SHAPE_TYPE_TO_RESPONSE_TYPE from './responseTypeMapping'; diff --git a/packages/rest-hooks/src/state/actions/createReceiveError.ts b/packages/core/src/state/actions/createReceiveError.ts similarity index 85% rename from packages/rest-hooks/src/state/actions/createReceiveError.ts rename to packages/core/src/state/actions/createReceiveError.ts index e5b1803724f..92e975fb552 100644 --- a/packages/rest-hooks/src/state/actions/createReceiveError.ts +++ b/packages/core/src/state/actions/createReceiveError.ts @@ -1,5 +1,9 @@ -import { Schema } from 'rest-hooks/resource'; -import { FetchAction, ResponseActions, FetchOptions } from 'rest-hooks/types'; +import { Schema } from '@rest-hooks/normalizr'; +import { + FetchAction, + ResponseActions, + FetchOptions, +} from '@rest-hooks/core/types'; import SHAPE_TYPE_TO_RESPONSE_TYPE from './responseTypeMapping'; diff --git a/packages/rest-hooks/src/state/actions/index.ts b/packages/core/src/state/actions/index.ts similarity index 100% rename from packages/rest-hooks/src/state/actions/index.ts rename to packages/core/src/state/actions/index.ts diff --git a/packages/rest-hooks/src/state/actions/responseTypeMapping.ts b/packages/core/src/state/actions/responseTypeMapping.ts similarity index 53% rename from packages/rest-hooks/src/state/actions/responseTypeMapping.ts rename to packages/core/src/state/actions/responseTypeMapping.ts index 5ca3ac95ae3..6fc13574cca 100644 --- a/packages/rest-hooks/src/state/actions/responseTypeMapping.ts +++ b/packages/core/src/state/actions/responseTypeMapping.ts @@ -1,6 +1,9 @@ -import { FetchShape } from 'rest-hooks/resource'; -import { ReceiveTypes } from 'rest-hooks/types'; -import { RECEIVE_TYPE, RECEIVE_DELETE_TYPE } from 'rest-hooks/actionTypes'; +import { FetchShape } from '@rest-hooks/core/endpoint'; +import { ReceiveTypes } from '@rest-hooks/core/types'; +import { + RECEIVE_TYPE, + RECEIVE_DELETE_TYPE, +} from '@rest-hooks/core/actionTypes'; const SHAPE_TYPE_TO_RESPONSE_TYPE: Record< FetchShape['type'], diff --git a/packages/rest-hooks/src/state/applyUpdatersToResults.ts b/packages/core/src/state/applyUpdatersToResults.ts similarity index 86% rename from packages/rest-hooks/src/state/applyUpdatersToResults.ts rename to packages/core/src/state/applyUpdatersToResults.ts index dd5274cf3bc..3a089c0688d 100644 --- a/packages/rest-hooks/src/state/applyUpdatersToResults.ts +++ b/packages/core/src/state/applyUpdatersToResults.ts @@ -1,5 +1,5 @@ -import { UpdateFunction } from 'rest-hooks/types'; -import { Normalize, Schema } from 'rest-hooks/resource'; +import { UpdateFunction } from '@rest-hooks/core/types'; +import { Normalize, Schema } from '@rest-hooks/normalizr'; type ResultStateFromUpdateFunctions< SourceSchema extends Schema, diff --git a/packages/rest-hooks/src/state/merge/isMergeable.ts b/packages/core/src/state/merge/isMergeable.ts similarity index 100% rename from packages/rest-hooks/src/state/merge/isMergeable.ts rename to packages/core/src/state/merge/isMergeable.ts diff --git a/packages/rest-hooks/src/state/merge/mergeDeepCopy.ts b/packages/core/src/state/merge/mergeDeepCopy.ts similarity index 100% rename from packages/rest-hooks/src/state/merge/mergeDeepCopy.ts rename to packages/core/src/state/merge/mergeDeepCopy.ts diff --git a/packages/rest-hooks/src/state/reducer.ts b/packages/core/src/state/reducer.ts similarity index 94% rename from packages/rest-hooks/src/state/reducer.ts rename to packages/core/src/state/reducer.ts index 98284a0d469..22fd12a8b59 100644 --- a/packages/rest-hooks/src/state/reducer.ts +++ b/packages/core/src/state/reducer.ts @@ -1,13 +1,13 @@ -import { normalize } from 'rest-hooks/resource'; -import { ActionTypes, State, ResponseActions } from 'rest-hooks/types'; -import { createReceive } from 'rest-hooks/state/actions'; +import { normalize } from '@rest-hooks/normalizr'; +import { ActionTypes, State, ResponseActions } from '@rest-hooks/core/types'; +import { createReceive } from '@rest-hooks/core/state/actions'; import { RECEIVE_TYPE, RECEIVE_DELETE_TYPE, INVALIDATE_TYPE, RESET_TYPE, FETCH_TYPE, -} from 'rest-hooks/actionTypes'; +} from '@rest-hooks/core/actionTypes'; import applyUpdatersToResults from './applyUpdatersToResults'; import mergeDeepCopy from './merge/mergeDeepCopy'; diff --git a/packages/rest-hooks/src/state/selectors/__tests__/__snapshots__/useDenormalized.ts.snap b/packages/core/src/state/selectors/__tests__/__snapshots__/useDenormalized.ts.snap similarity index 100% rename from packages/rest-hooks/src/state/selectors/__tests__/__snapshots__/useDenormalized.ts.snap rename to packages/core/src/state/selectors/__tests__/__snapshots__/useDenormalized.ts.snap diff --git a/packages/rest-hooks/src/state/selectors/__tests__/buildInferredResults.ts b/packages/core/src/state/selectors/__tests__/buildInferredResults.ts similarity index 98% rename from packages/rest-hooks/src/state/selectors/__tests__/buildInferredResults.ts rename to packages/core/src/state/selectors/__tests__/buildInferredResults.ts index 3b9c566ea73..13300a33404 100644 --- a/packages/rest-hooks/src/state/selectors/__tests__/buildInferredResults.ts +++ b/packages/core/src/state/selectors/__tests__/buildInferredResults.ts @@ -3,8 +3,8 @@ import { UnionResource, IndexedUserResource, } from '__tests__/common'; +import { schema as schemas } from '@rest-hooks/normalizr'; -import { schemas } from '../../../resource'; import buildInferredResults from '../buildInferredResults'; describe('buildInferredResults()', () => { diff --git a/packages/rest-hooks/src/state/selectors/__tests__/getEntityPath.ts b/packages/core/src/state/selectors/__tests__/getEntityPath.ts similarity index 96% rename from packages/rest-hooks/src/state/selectors/__tests__/getEntityPath.ts rename to packages/core/src/state/selectors/__tests__/getEntityPath.ts index 5186a35f19b..bdb0471c0ee 100644 --- a/packages/rest-hooks/src/state/selectors/__tests__/getEntityPath.ts +++ b/packages/core/src/state/selectors/__tests__/getEntityPath.ts @@ -1,6 +1,6 @@ import { CoolerArticleResource } from '__tests__/common'; +import { schema as schemas } from '@rest-hooks/normalizr'; -import { schemas } from '../../../resource/normal'; import getEntityPath from '../getEntityPath'; describe('getEntityPath()', () => { diff --git a/packages/rest-hooks/src/state/selectors/__tests__/useDenormalized.ts b/packages/core/src/state/selectors/__tests__/useDenormalized.ts similarity index 99% rename from packages/rest-hooks/src/state/selectors/__tests__/useDenormalized.ts rename to packages/core/src/state/selectors/__tests__/useDenormalized.ts index 4f6f7dade1f..3f77ed49615 100644 --- a/packages/rest-hooks/src/state/selectors/__tests__/useDenormalized.ts +++ b/packages/core/src/state/selectors/__tests__/useDenormalized.ts @@ -6,8 +6,8 @@ import { IndexedUserResource, photoShape, } from '__tests__/common'; -import { normalize, NormalizedIndex } from 'rest-hooks/resource'; -import { initialState } from 'rest-hooks/state/reducer'; +import { normalize, NormalizedIndex } from '@rest-hooks/normalizr'; +import { initialState } from '@rest-hooks/core/state/reducer'; import { renderHook, act } from '@testing-library/react-hooks'; import { useState } from 'react'; diff --git a/packages/rest-hooks/src/state/selectors/buildInferredResults.ts b/packages/core/src/state/selectors/buildInferredResults.ts similarity index 92% rename from packages/rest-hooks/src/state/selectors/buildInferredResults.ts rename to packages/core/src/state/selectors/buildInferredResults.ts index 9338f475421..e9c46afcb7c 100644 --- a/packages/rest-hooks/src/state/selectors/buildInferredResults.ts +++ b/packages/core/src/state/selectors/buildInferredResults.ts @@ -1,5 +1,10 @@ -import { NormalizedIndex, isEntity } from '@rest-hooks/normalizr'; -import { Schema, schemas, NormalizeNullable } from 'rest-hooks/resource'; +import { + NormalizedIndex, + isEntity, + Schema, + schema as schemas, +} from '@rest-hooks/normalizr'; +import { NormalizeNullable } from '@rest-hooks/core/endpoint/normal'; /** * Build the result parameter to denormalize from schema alone. diff --git a/packages/rest-hooks/src/state/selectors/getEntityPath.ts b/packages/core/src/state/selectors/getEntityPath.ts similarity index 82% rename from packages/rest-hooks/src/state/selectors/getEntityPath.ts rename to packages/core/src/state/selectors/getEntityPath.ts index 26c7e5e9b9c..6d3d7968b37 100644 --- a/packages/rest-hooks/src/state/selectors/getEntityPath.ts +++ b/packages/core/src/state/selectors/getEntityPath.ts @@ -1,5 +1,4 @@ -import { isEntity } from '@rest-hooks/normalizr'; -import { Schema, schemas } from 'rest-hooks/resource/normal'; +import { isEntity, Schema, schema as schemas } from '@rest-hooks/normalizr'; export default function getEntityPath(schema: Schema): string[] | false { if ( diff --git a/packages/rest-hooks/src/state/selectors/index.ts b/packages/core/src/state/selectors/index.ts similarity index 79% rename from packages/rest-hooks/src/state/selectors/index.ts rename to packages/core/src/state/selectors/index.ts index 098457bd16d..6a59cf1fa5c 100644 --- a/packages/rest-hooks/src/state/selectors/index.ts +++ b/packages/core/src/state/selectors/index.ts @@ -1,4 +1,4 @@ -import { State } from 'rest-hooks/types'; +import { State } from '@rest-hooks/core/types'; import useDenormalized from './useDenormalized'; diff --git a/packages/rest-hooks/src/state/selectors/useDenormalized.ts b/packages/core/src/state/selectors/useDenormalized.ts similarity index 94% rename from packages/rest-hooks/src/state/selectors/useDenormalized.ts rename to packages/core/src/state/selectors/useDenormalized.ts index 1c10fe0e70f..e6e5dd4c579 100644 --- a/packages/rest-hooks/src/state/selectors/useDenormalized.ts +++ b/packages/core/src/state/selectors/useDenormalized.ts @@ -1,14 +1,13 @@ -import { State } from 'rest-hooks/types'; +import { State } from '@rest-hooks/core/types'; import { ReadShape, - denormalize, DenormalizeNullable, ParamsFromShape, -} from 'rest-hooks/resource'; -import { isEntity, Schema } from '@rest-hooks/normalizr'; +} from '@rest-hooks/core/endpoint'; +import { isEntity, Schema, denormalize } from '@rest-hooks/normalizr'; import { useMemo } from 'react'; +import hasUsableData from '@rest-hooks/core/react-integration/hooks/hasUsableData'; -import hasUsableData from '../../react-integration/hooks/hasUsableData'; import buildInferredResults from './buildInferredResults'; /** diff --git a/packages/rest-hooks/src/types.ts b/packages/core/src/types.ts similarity index 95% rename from packages/rest-hooks/src/types.ts rename to packages/core/src/types.ts index bada9b2c70d..acd09fca466 100644 --- a/packages/rest-hooks/src/types.ts +++ b/packages/core/src/types.ts @@ -1,10 +1,15 @@ import { NormalizedIndex } from '@rest-hooks/normalizr'; -import type { AbstractInstanceType } from '@rest-hooks/normalizr'; +import type { + AbstractInstanceType, + Schema, + Normalize, +} from '@rest-hooks/normalizr'; +import { schema } from '@rest-hooks/normalizr'; import { Middleware } from '@rest-hooks/use-enhanced-reducer'; import { FSAWithPayloadAndMeta, FSAWithMeta, FSA } from 'flux-standard-action'; import { ErrorableFSAWithPayloadAndMeta, ErrorableFSAWithMeta } from './fsa'; -import { Schema, schemas, Normalize, FetchShape } from './resource'; +import { FetchShape } from './endpoint'; import { RECEIVE_TYPE, RECEIVE_DELETE_TYPE, @@ -75,7 +80,7 @@ export type ReceiveAction< >; interface PurgeMeta { - schema: schemas.EntityInterface; + schema: schema.EntityInterface; key: string; date: number; } diff --git a/packages/core/tsconfig.compile.json b/packages/core/tsconfig.compile.json new file mode 100644 index 00000000000..c84bf15512e --- /dev/null +++ b/packages/core/tsconfig.compile.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig", + "compilerOptions": { + "paths": { + "@rest-hooks/core/*": ["packages/core/src/*"] + } + }, + "exclude": ["node_modules", "dist", "lib", "**/__tests__"] +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 00000000000..c96ae89d67e --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig-base", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src" + }, + "include": ["src"], + "references": [ + { "path": "../../__tests__" }, + { "path": "../normalizr" }, + { "path": "../use-enhanced-reducer" } + ] +} diff --git a/packages/core/typescript.svg b/packages/core/typescript.svg new file mode 100644 index 00000000000..52748150d26 --- /dev/null +++ b/packages/core/typescript.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/legacy/package.json b/packages/legacy/package.json index d9a17aefd04..3fcf6eeb03d 100644 --- a/packages/legacy/package.json +++ b/packages/legacy/package.json @@ -61,7 +61,7 @@ "peerDependencies": { "@types/react": "^16.8.2", "react": "^16.8.2", - "rest-hooks": "^5.0.0-beta.5" + "@rest-hooks/core": "^1.0.0-beta.0" }, "peerDependenciesMeta": { "@types/react": { diff --git a/packages/legacy/src/index.ts b/packages/legacy/src/index.ts index fb5a7569fd6..48850361cb4 100644 --- a/packages/legacy/src/index.ts +++ b/packages/legacy/src/index.ts @@ -4,8 +4,9 @@ import { Schema, ReadShape, useDenormalized, - __INTERNAL__, -} from 'rest-hooks'; + StateContext, + hasUsableData, +} from '@rest-hooks/core'; import { useContext } from 'react'; /** Ensure a resource is available; loading and error returned explicitly. */ @@ -14,7 +15,7 @@ export function useStatefulResource< S extends Schema >(fetchShape: ReadShape, params: Params | null) { const maybePromise = useRetrieve(fetchShape, params); - const state = useContext(__INTERNAL__.StateContext); + const state = useContext(StateContext); const expired = !!maybePromise && typeof maybePromise.then === 'function'; const [denormalized, ready] = useDenormalized( fetchShape, @@ -23,7 +24,7 @@ export function useStatefulResource< expired, ); - const loading = !__INTERNAL__.hasUsableData(ready, fetchShape) && expired; + const loading = !hasUsableData(ready, fetchShape) && expired; const error = useError(fetchShape, params, ready); return { diff --git a/packages/legacy/tsconfig.json b/packages/legacy/tsconfig.json index e0690fd3a8d..552a6f9553d 100644 --- a/packages/legacy/tsconfig.json +++ b/packages/legacy/tsconfig.json @@ -6,7 +6,7 @@ }, "include": ["src"], "references": [ - { "path": "../rest-hooks" }, + { "path": "../core" }, { "path": "../test" } ] } diff --git a/packages/rest-hooks/package.json b/packages/rest-hooks/package.json index b9caafcd861..b19fd7145bf 100644 --- a/packages/rest-hooks/package.json +++ b/packages/rest-hooks/package.json @@ -64,9 +64,7 @@ }, "dependencies": { "@babel/runtime": "^7.7.2", - "@rest-hooks/normalizr": "^6.0.0-beta.2", - "@rest-hooks/use-enhanced-reducer": "^1.0.3", - "flux-standard-action": "^2.1.1" + "@rest-hooks/core": "^1.0.0-beta.0" }, "peerDependencies": { "@types/react": "^16.8.2", diff --git a/packages/rest-hooks/rollup.config.js b/packages/rest-hooks/rollup.config.js index 28bb6744291..56a728e1977 100644 --- a/packages/rest-hooks/rollup.config.js +++ b/packages/rest-hooks/rollup.config.js @@ -10,14 +10,7 @@ import pkg from './package.json'; const dependencies = Object.keys(pkg.dependencies) .concat(Object.keys(pkg.peerDependencies)) - .filter( - dep => - ![ - '@rest-hooks/normalizr', - '@rest-hooks/use-enhanced-reducer', - '@babel/runtime', - ].includes(dep), - ); + .filter(dep => !['@babel/runtime'].includes(dep)); const extensions = ['.js', '.ts', '.tsx', '.mjs', '.json', '.node']; const nativeExtensions = ['.native.ts', ...extensions]; diff --git a/packages/rest-hooks/src/index.ts b/packages/rest-hooks/src/index.ts index 1b1df9e51fc..fc287e2ab8e 100644 --- a/packages/rest-hooks/src/index.ts +++ b/packages/rest-hooks/src/index.ts @@ -1,12 +1,19 @@ -import { Resource, SimpleResource, SimpleRecord } from './resource'; -import NetworkManager from './state/NetworkManager'; -import RIC from './state/RIC'; -import PollingSubscription from './state/PollingSubscription'; -import SubscriptionManager from './state/SubscriptionManager'; -import reducer, { initialState } from './state/reducer'; -import { useDenormalized } from './state/selectors'; -import buildInferredResults from './state/selectors/buildInferredResults'; import { + initialState, + StateContext, + DispatchContext, + hasUsableData, + __INTERNAL__ as _INT_, +} from '@rest-hooks/core'; + +export { + Entity as NestedEntity, + isEntity, + FlatEntity as Entity, + schema as schemas, +} from '@rest-hooks/normalizr'; + +export { useCache, useFetcher, useRetrieve, @@ -17,22 +24,59 @@ import { CacheProvider, useInvalidator, useResetter, + useDenormalized, + SimpleRecord, + // TODO: get rid of these exports once core has been out for a while + usePromisifiedDispatch, +} from '@rest-hooks/core'; +export type { + FetchShape, + ReadShape, + MutateShape, + DeleteShape, + SetShapeParams, + ParamsFromShape, + AbstractInstanceType, + FetchOptions, + Method, + UpdateFunction, + // TODO: get rid of these exports once core has been out for a while + FetchAction, + InvalidateAction, + UnsubscribeAction, + SubscribeAction, + PurgeAction, + ResetAction, + ReceiveAction, + State, + ReceiveTypes, + PK, + Dispatch, + Middleware, + MiddlewareAPI, + ActionTypes, + Manager, + Schema, +} from '@rest-hooks/core'; +export { Resource, SimpleResource } from './resource'; +export type { SchemaDetail, SchemaList } from './resource/types'; +export { ExternalCacheProvider, PromiseifyMiddleware, NetworkErrorBoundary, - NetworkError as OGNetworkError, } from './react-integration'; -import useSelectionUnstable from './react-integration/hooks/useSelection'; -import hasUsableData from './react-integration/hooks/hasUsableData'; -import { StateContext, DispatchContext } from './react-integration/context'; +export type { NetworkError } from './react-integration'; export { - Entity as NestedEntity, - isEntity, - FlatEntity as Entity, -} from '@rest-hooks/normalizr'; + PollingSubscription, + SubscriptionManager, + DefaultConnectionListener, +} from './manager'; +export type { ConnectionListener } from './manager'; +export { default as useSelectionUnstable } from './react-integration/hooks/useSelection'; -const __INTERNAL__ = { +const { buildInferredResults, RIC } = _INT_; +export const __INTERNAL__ = { initialState, StateContext, DispatchContext, @@ -40,44 +84,3 @@ const __INTERNAL__ = { hasUsableData, buildInferredResults, }; - -export type NetworkError = OGNetworkError; - -export * from './state/actions'; -export * as actionTypes from './actionTypes'; -export * from '@rest-hooks/use-enhanced-reducer'; -/* istanbul ignore next */ -export * from './types'; -export type { - FetchShape, - ReadShape, - MutateShape, - DeleteShape, -} from './resource/shapes'; -export * from './resource/normal'; -export type { SetShapeParams, ParamsFromShape } from './resource/publicTypes'; -export { - Resource, - SimpleResource, - SimpleRecord, - CacheProvider, - ExternalCacheProvider, - PromiseifyMiddleware, - useCache, - useFetcher, - useRetrieve, - useInvalidator, - useResetter, - useResource, - useSubscription, - useMeta, - useError, - useSelectionUnstable, - useDenormalized, - NetworkManager, - SubscriptionManager, - PollingSubscription, - reducer, - NetworkErrorBoundary, - __INTERNAL__, -}; diff --git a/packages/rest-hooks/src/state/ConnectionListener.ts b/packages/rest-hooks/src/manager/ConnectionListener.ts similarity index 84% rename from packages/rest-hooks/src/state/ConnectionListener.ts rename to packages/rest-hooks/src/manager/ConnectionListener.ts index 7e8b916d867..e8a754a3183 100644 --- a/packages/rest-hooks/src/state/ConnectionListener.ts +++ b/packages/rest-hooks/src/manager/ConnectionListener.ts @@ -1,4 +1,4 @@ -export interface ConnectionListener { +export default interface ConnectionListener { isOnline: () => boolean; addOnlineListener: (handler: () => void) => void; removeOnlineListener: (handler: () => void) => void; diff --git a/packages/rest-hooks/src/state/DefaultConnectionListener.ts b/packages/rest-hooks/src/manager/DefaultConnectionListener.ts similarity index 95% rename from packages/rest-hooks/src/state/DefaultConnectionListener.ts rename to packages/rest-hooks/src/manager/DefaultConnectionListener.ts index 0eccef8c812..1ce3f871777 100644 --- a/packages/rest-hooks/src/state/DefaultConnectionListener.ts +++ b/packages/rest-hooks/src/manager/DefaultConnectionListener.ts @@ -1,4 +1,4 @@ -import { ConnectionListener } from './ConnectionListener'; +import ConnectionListener from './ConnectionListener'; export class BrowserConnectionListener implements ConnectionListener { isOnline() { diff --git a/packages/rest-hooks/src/state/PollingSubscription.ts b/packages/rest-hooks/src/manager/PollingSubscription.ts similarity index 94% rename from packages/rest-hooks/src/state/PollingSubscription.ts rename to packages/rest-hooks/src/manager/PollingSubscription.ts index 9b989e6acd7..97fd6d5806f 100644 --- a/packages/rest-hooks/src/state/PollingSubscription.ts +++ b/packages/rest-hooks/src/manager/PollingSubscription.ts @@ -1,11 +1,11 @@ -import { Schema } from 'rest-hooks/resource'; -import { Dispatch } from '@rest-hooks/use-enhanced-reducer'; -import { FETCH_TYPE, RECEIVE_TYPE } from 'rest-hooks/actionTypes'; -import { createFetch } from 'rest-hooks/state/actions'; +import { Schema } from '@rest-hooks/normalizr'; +import { actionTypes, Dispatch } from '@rest-hooks/core'; import { Subscription, SubscriptionInit } from './SubscriptionManager'; import DefaultConnectionListener from './DefaultConnectionListener'; -import { ConnectionListener } from './ConnectionListener'; +import ConnectionListener from './ConnectionListener'; + +const { FETCH_TYPE } = actionTypes; /** * PollingSubscription keeps a given resource updated by diff --git a/packages/rest-hooks/src/state/SubscriptionManager.ts b/packages/rest-hooks/src/manager/SubscriptionManager.ts similarity index 93% rename from packages/rest-hooks/src/state/SubscriptionManager.ts rename to packages/rest-hooks/src/manager/SubscriptionManager.ts index 8ae6b3d4834..4fe9297b7ef 100644 --- a/packages/rest-hooks/src/state/SubscriptionManager.ts +++ b/packages/rest-hooks/src/manager/SubscriptionManager.ts @@ -2,10 +2,14 @@ import { MiddlewareAPI, Middleware, Dispatch, -} from '@rest-hooks/use-enhanced-reducer'; -import { SubscribeAction, UnsubscribeAction, Manager } from 'rest-hooks/types'; -import { SUBSCRIBE_TYPE, UNSUBSCRIBE_TYPE } from 'rest-hooks/actionTypes'; -import { Schema } from 'rest-hooks/resource'; + SubscribeAction, + UnsubscribeAction, + Manager, + actionTypes, +} from '@rest-hooks/core'; +import { Schema } from '@rest-hooks/normalizr'; + +const { SUBSCRIBE_TYPE, UNSUBSCRIBE_TYPE } = actionTypes; type Actions = UnsubscribeAction | SubscribeAction; diff --git a/packages/rest-hooks/src/state/__tests__/__snapshots__/pollingSubscription.ts.snap b/packages/rest-hooks/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap similarity index 100% rename from packages/rest-hooks/src/state/__tests__/__snapshots__/pollingSubscription.ts.snap rename to packages/rest-hooks/src/manager/__tests__/__snapshots__/pollingSubscription.ts.snap diff --git a/packages/rest-hooks/src/state/__tests__/pollingSubscription.ts b/packages/rest-hooks/src/manager/__tests__/pollingSubscription.ts similarity index 99% rename from packages/rest-hooks/src/state/__tests__/pollingSubscription.ts rename to packages/rest-hooks/src/manager/__tests__/pollingSubscription.ts index 4932447ff9e..50069a4cecc 100644 --- a/packages/rest-hooks/src/state/__tests__/pollingSubscription.ts +++ b/packages/rest-hooks/src/manager/__tests__/pollingSubscription.ts @@ -2,7 +2,7 @@ import { PollingArticleResource } from '__tests__/common'; import PollingSubscription from '../PollingSubscription'; import DefaultConnectionListener from '../DefaultConnectionListener'; -import { ConnectionListener } from '../ConnectionListener'; +import ConnectionListener from '../ConnectionListener'; class MockConnectionListener implements ConnectionListener { declare online: boolean; diff --git a/packages/rest-hooks/src/state/__tests__/subscriptionManager.ts b/packages/rest-hooks/src/manager/__tests__/subscriptionManager.ts similarity index 97% rename from packages/rest-hooks/src/state/__tests__/subscriptionManager.ts rename to packages/rest-hooks/src/manager/__tests__/subscriptionManager.ts index c763bef3d26..523cebf4822 100644 --- a/packages/rest-hooks/src/state/__tests__/subscriptionManager.ts +++ b/packages/rest-hooks/src/manager/__tests__/subscriptionManager.ts @@ -1,12 +1,13 @@ import { PollingArticleResource } from '__tests__/common'; +import { + SubscribeAction, + UnsubscribeAction, + actionTypes, +} from '@rest-hooks/core'; import SubscriptionManager, { Subscription } from '../SubscriptionManager'; -import { SubscribeAction, UnsubscribeAction } from '../../types'; -import { - UNSUBSCRIBE_TYPE, - SUBSCRIBE_TYPE, - RECEIVE_TYPE, -} from '../../actionTypes'; + +const { UNSUBSCRIBE_TYPE, SUBSCRIBE_TYPE, RECEIVE_TYPE } = actionTypes; function onError(e: any) { e.preventDefault(); diff --git a/packages/rest-hooks/src/manager/index.ts b/packages/rest-hooks/src/manager/index.ts new file mode 100644 index 00000000000..c540f18755c --- /dev/null +++ b/packages/rest-hooks/src/manager/index.ts @@ -0,0 +1,4 @@ +export type { default as ConnectionListener } from './ConnectionListener'; +export { default as DefaultConnectionListener } from './DefaultConnectionListener'; +export { default as PollingSubscription } from './PollingSubscription'; +export { default as SubscriptionManager } from './SubscriptionManager'; diff --git a/packages/rest-hooks/src/react-integration/__tests__/provider.tsx b/packages/rest-hooks/src/react-integration/__tests__/provider.tsx new file mode 100644 index 00000000000..a7a6392f480 --- /dev/null +++ b/packages/rest-hooks/src/react-integration/__tests__/provider.tsx @@ -0,0 +1,20 @@ +import { SubscriptionManager } from 'rest-hooks/manager'; +import { CacheProvider as CoreCacheProvider } from '@rest-hooks/core'; + +import { CacheProvider } from '../provider'; + +describe('CacheProvider', () => { + it('should have SubscriptionManager in default managers', () => { + const subManagers = CacheProvider.defaultProps.managers.filter( + manager => manager instanceof SubscriptionManager, + ); + expect(subManagers.length).toBe(1); + }); + + it('from core should not have SubscriptionManager in default managers', () => { + const subManagers = CoreCacheProvider.defaultProps.managers.filter( + manager => manager instanceof SubscriptionManager, + ); + expect(subManagers.length).toBe(0); + }); +}); diff --git a/packages/rest-hooks/src/react-integration/hooks/useSelection.ts b/packages/rest-hooks/src/react-integration/hooks/useSelection.ts index b36b6172701..fd9a2b217a4 100644 --- a/packages/rest-hooks/src/react-integration/hooks/useSelection.ts +++ b/packages/rest-hooks/src/react-integration/hooks/useSelection.ts @@ -1,6 +1,5 @@ import { useContext, useMemo } from 'react'; -import { StateContext } from 'rest-hooks/react-integration/context'; -import { State } from 'rest-hooks/types'; +import { StateContext, State } from '@rest-hooks/core'; /** Use selector to access part of state */ export default function useSelectionUnstable< diff --git a/packages/rest-hooks/src/react-integration/index.ts b/packages/rest-hooks/src/react-integration/index.ts index b5da549a45d..25b381f2181 100644 --- a/packages/rest-hooks/src/react-integration/index.ts +++ b/packages/rest-hooks/src/react-integration/index.ts @@ -1,6 +1,6 @@ import NetworkErrorBoundary from './NetworkErrorBoundary'; export * from './provider'; -export * from './hooks'; +export { default as useSelectionUnstable } from './hooks/useSelection'; export type { NetworkError } from './NetworkErrorBoundary'; export { NetworkErrorBoundary }; diff --git a/packages/rest-hooks/src/react-integration/provider/ExternalCacheProvider.tsx b/packages/rest-hooks/src/react-integration/provider/ExternalCacheProvider.tsx index eb6ffc4c425..b91d5090965 100644 --- a/packages/rest-hooks/src/react-integration/provider/ExternalCacheProvider.tsx +++ b/packages/rest-hooks/src/react-integration/provider/ExternalCacheProvider.tsx @@ -1,9 +1,10 @@ import { StateContext, DispatchContext, -} from 'rest-hooks/react-integration/context'; -import masterReducer from 'rest-hooks/state/reducer'; -import { State, ActionTypes } from 'rest-hooks/types'; + reducer, + State, + ActionTypes, +} from '@rest-hooks/core'; import { usePromisifiedDispatch } from '@rest-hooks/use-enhanced-reducer'; import React, { ReactNode, useEffect, useState, useMemo } from 'react'; @@ -26,7 +27,7 @@ export default function ExternalCacheProvider({ const [state, setState] = useState(() => selector(store.getState())); const optimisticState = useMemo( - () => state.optimistic.reduce(masterReducer, state), + () => state.optimistic.reduce(reducer, state), [state], ); diff --git a/packages/rest-hooks/src/react-integration/provider/index.ts b/packages/rest-hooks/src/react-integration/provider/index.ts index b3e130cb6ca..789e83a5a14 100644 --- a/packages/rest-hooks/src/react-integration/provider/index.ts +++ b/packages/rest-hooks/src/react-integration/provider/index.ts @@ -1,5 +1,16 @@ +import { CacheProvider as CoreCacheProvider } from '@rest-hooks/core'; +import { SubscriptionManager, PollingSubscription } from 'rest-hooks/manager'; + import PromiseifyMiddleware from './PromiseifyMiddleware'; -import CacheProvider from './CacheProvider'; import ExternalCacheProvider from './ExternalCacheProvider'; +const CacheProvider: typeof CoreCacheProvider = props => CacheProvider(props); +CacheProvider.defaultProps = { + ...CoreCacheProvider.defaultProps, + managers: [ + ...CoreCacheProvider.defaultProps.managers, + new SubscriptionManager(PollingSubscription), + ], +}; + export { CacheProvider, ExternalCacheProvider, PromiseifyMiddleware }; diff --git a/packages/rest-hooks/src/resource/Resource.ts b/packages/rest-hooks/src/resource/Resource.ts index 96d1e662ec6..dc6e9ae740d 100644 --- a/packages/rest-hooks/src/resource/Resource.ts +++ b/packages/rest-hooks/src/resource/Resource.ts @@ -1,4 +1,4 @@ -import { Method } from 'rest-hooks/types'; +import type { Method } from '@rest-hooks/core'; import SimpleResource from './SimpleResource'; diff --git a/packages/rest-hooks/src/resource/SimpleResource.ts b/packages/rest-hooks/src/resource/SimpleResource.ts index f026ff09748..431e9896fc8 100644 --- a/packages/rest-hooks/src/resource/SimpleResource.ts +++ b/packages/rest-hooks/src/resource/SimpleResource.ts @@ -1,9 +1,15 @@ -import { AbstractInstanceType, Method, FetchOptions } from 'rest-hooks/types'; import { FlatEntity } from '@rest-hooks/normalizr'; +import type { + FetchOptions, + AbstractInstanceType, + Method, + ReadShape, + MutateShape, + DeleteShape, +} from '@rest-hooks/core'; +import { SchemaDetail, SchemaList } from './types'; import { NotImplementedError } from './errors'; -import { ReadShape, MutateShape, DeleteShape } from './shapes'; -import { SchemaDetail, SchemaList } from './normal'; import paramsToString from './paramsToString'; /** Represents an entity to be retrieved from a server. @@ -100,6 +106,7 @@ export default abstract class SimpleResource extends FlatEntity { 'getEntitySchema() is deprecated - use Entity directly instead.', ); } + /* istanbul ignore next */ return this; } diff --git a/packages/rest-hooks/src/resource/__tests__/resource.ts b/packages/rest-hooks/src/resource/__tests__/resource.ts index 1dfc4aece6b..dd97551b17f 100644 --- a/packages/rest-hooks/src/resource/__tests__/resource.ts +++ b/packages/rest-hooks/src/resource/__tests__/resource.ts @@ -4,8 +4,8 @@ import { UrlArticleResource, } from '__tests__/common'; import nock from 'nock'; +import { normalize } from '@rest-hooks/normalizr'; -import { normalize } from '../normal'; import Resource from '../Resource'; import SimpleResource from '../SimpleResource'; diff --git a/packages/rest-hooks/src/resource/index.ts b/packages/rest-hooks/src/resource/index.ts index c2861784132..d6902542929 100644 --- a/packages/rest-hooks/src/resource/index.ts +++ b/packages/rest-hooks/src/resource/index.ts @@ -1,14 +1,6 @@ import Resource from './Resource'; import SimpleResource from './SimpleResource'; -export type { FetchShape, ReadShape, MutateShape, DeleteShape } from './shapes'; -export * from './types'; -export type { - SetShapeParams, - ParamsFromShape, - OptimisticUpdateParams, - SchemaFromShape, - BodyFromShape, -} from './publicTypes'; -export * from './normal'; + +export type { SchemaDetail, SchemaList } from './types'; export { Resource, SimpleResource }; diff --git a/packages/rest-hooks/src/resource/types.ts b/packages/rest-hooks/src/resource/types.ts index 359e88e016f..6cc09130a5e 100644 --- a/packages/rest-hooks/src/resource/types.ts +++ b/packages/rest-hooks/src/resource/types.ts @@ -1,25 +1,12 @@ -import { FetchShape, DeleteShape } from './shapes'; +import { schema as schemas, Schema } from '@rest-hooks/normalizr'; -export function isDeleteShape( - shape: FetchShape, -): shape is DeleteShape { - return shape.type === 'delete'; -} +export type SchemaDetail = + | schemas.EntityInterface + | { [K: string]: any } + | schemas.SchemaClass; -export type ResultShape = RS extends { schema: infer U } ? U : never; -export type SelectReturn = RS extends { - select: (...args: any[]) => infer U; -} - ? U - : never; -export type AlwaysSelect = NonNullable>; -export type ParamArg = RS extends { - getFetchKey: (params: infer U) => any; -} - ? U - : never; -export type BodyArg = RS extends { - fetch: (url: any, body: infer U) => any; -} - ? U - : never; +export type SchemaList = + | schemas.EntityInterface[] + | { [K: string]: any } + | Schema[] + | schemas.SchemaClass; diff --git a/packages/rest-hooks/tsconfig.json b/packages/rest-hooks/tsconfig.json index c96ae89d67e..1886bc5ac63 100644 --- a/packages/rest-hooks/tsconfig.json +++ b/packages/rest-hooks/tsconfig.json @@ -7,7 +7,7 @@ "include": ["src"], "references": [ { "path": "../../__tests__" }, - { "path": "../normalizr" }, - { "path": "../use-enhanced-reducer" } + { "path": "../use-enhanced-reducer" }, + { "path": "../core" }, ] } diff --git a/packages/test/src/MockProvider.tsx b/packages/test/src/MockProvider.tsx index 799f110530d..84c39a57859 100644 --- a/packages/test/src/MockProvider.tsx +++ b/packages/test/src/MockProvider.tsx @@ -1,8 +1,8 @@ -import { __INTERNAL__, ActionTypes } from 'rest-hooks'; +import { StateContext, DispatchContext } from '@rest-hooks/core'; +import type { ActionTypes } from '@rest-hooks/core'; import React from 'react'; import mockState, { Fixture } from './mockState'; -const { StateContext, DispatchContext } = __INTERNAL__; const mockDispatch = (value: ActionTypes) => { console.error( diff --git a/packages/test/src/makeRenderRestHook.tsx b/packages/test/src/makeRenderRestHook.tsx index 7c69c5f6735..9682d694257 100644 --- a/packages/test/src/makeRenderRestHook.tsx +++ b/packages/test/src/makeRenderRestHook.tsx @@ -1,4 +1,5 @@ -import { State, SubscriptionManager, Manager } from 'rest-hooks'; +import { State, Manager } from '@rest-hooks/core'; +import { SubscriptionManager } from 'rest-hooks'; import React from 'react'; import { renderHook, RenderHookOptions } from '@testing-library/react-hooks'; diff --git a/packages/test/src/managers.ts b/packages/test/src/managers.ts index 04bc730e0c2..d493e353b92 100644 --- a/packages/test/src/managers.ts +++ b/packages/test/src/managers.ts @@ -1,10 +1,6 @@ -import { - NetworkManager, - FetchAction, - ReceiveAction, - Dispatch, - PollingSubscription, -} from 'rest-hooks'; +import { NetworkManager, FetchAction } from '@rest-hooks/core'; +import type { ReceiveAction, Dispatch } from '@rest-hooks/core'; +import { PollingSubscription } from 'rest-hooks'; import { act } from '@testing-library/react-hooks'; export class MockNetworkManager extends NetworkManager { diff --git a/packages/test/src/mockState.ts b/packages/test/src/mockState.ts index bf6a97595bf..26cdc1e6c8a 100644 --- a/packages/test/src/mockState.ts +++ b/packages/test/src/mockState.ts @@ -2,10 +2,9 @@ import { ReadShape, Schema, reducer, - __INTERNAL__, createReceive, -} from 'rest-hooks'; -const { initialState } = __INTERNAL__; + initialState, +} from '@rest-hooks/core'; export interface Fixture { request: ReadShape; diff --git a/packages/test/src/providers.tsx b/packages/test/src/providers.tsx index 0c0b582c7a8..b750f6b950a 100644 --- a/packages/test/src/providers.tsx +++ b/packages/test/src/providers.tsx @@ -1,11 +1,5 @@ -import { - State, - reducer, - ExternalCacheProvider, - CacheProvider, - Manager, - PromiseifyMiddleware, -} from 'rest-hooks'; +import { State, reducer, CacheProvider, Manager } from '@rest-hooks/core'; +import { ExternalCacheProvider, PromiseifyMiddleware } from 'rest-hooks'; import React from 'react'; // Extension of the DeepPartial type defined by Redux which handles unknown diff --git a/packages/test/tsconfig.json b/packages/test/tsconfig.json index 2402465abe6..199ddb4170c 100644 --- a/packages/test/tsconfig.json +++ b/packages/test/tsconfig.json @@ -5,5 +5,8 @@ "rootDir": "src" }, "include": ["src"], - "references": [{ "path": "../rest-hooks" }] + "references": [ + { "path": "../core" }, + { "path": "../rest-hooks" } + ] } diff --git a/tsconfig-base.json b/tsconfig-base.json index f6b1da0dc83..eba5d04f7ec 100644 --- a/tsconfig-base.json +++ b/tsconfig-base.json @@ -52,6 +52,7 @@ "baseUrl": ".", "paths": { + "@rest-hooks/core/*": ["packages/core/src/*"], "@rest-hooks/*": ["packages/*/src"], "rest-hooks": ["packages/rest-hooks/src"], "rest-hooks/*": ["packages/rest-hooks/src/*"], diff --git a/tsconfig.json b/tsconfig.json index 8c60743d779..7dad567e021 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "references": [ { "path": "./packages/normalizr/tsconfig.compile.json" }, { "path": "./packages/use-enhanced-reducer/tsconfig.compile.json" }, + { "path": "./packages/core/tsconfig.compile.json" }, { "path": "./packages/rest-hooks/tsconfig.compile.json" }, { "path": "./packages/test/tsconfig.compile.json" }, { "path": "./packages/legacy/tsconfig.compile.json" }