├── .prettierignore
├── packages
├── client
│ ├── test
│ │ ├── mocks
│ │ │ ├── foo.txt
│ │ │ └── MockTransport.ts
│ │ ├── namespace.spec.ts
│ │ ├── resource.spec.ts
│ │ ├── embed.spec.ts
│ │ ├── HTTPMethods.spec.ts
│ │ ├── slug.spec.ts
│ │ ├── param.spec.ts
│ │ ├── header.spec.ts
│ │ ├── discover.spec.ts
│ │ ├── file.spec.ts
│ │ ├── request.spec.ts
│ │ ├── Client.spec.ts
│ │ ├── Transport
│ │ │ └── index.spec.ts
│ │ └── middlewares.spec.ts
│ ├── jest.setup.js
│ ├── README.md
│ ├── jest.config.js
│ ├── src
│ │ ├── index.ts
│ │ ├── Client.types.ts
│ │ ├── Transport.types.ts
│ │ ├── Transport.ts
│ │ └── Client.ts
│ ├── tsconfig.json
│ ├── package.json
│ └── tsconfig.tsbuildinfo
├── react
│ ├── README.md
│ ├── jest.config.js
│ ├── src
│ │ ├── index.ts
│ │ ├── provider.types.ts
│ │ ├── provider.tsx
│ │ ├── withClient.tsx
│ │ └── useClient.ts
│ ├── tsconfig.json
│ ├── test
│ │ ├── withClient.spec.tsx
│ │ └── useClient.spec.tsx
│ └── package.json
└── support
│ ├── jest.config.js
│ ├── README.md
│ ├── tsconfig.json
│ ├── src
│ ├── HTTPError.ts
│ └── index.ts
│ ├── test
│ ├── HTTPError.spec.ts
│ └── index.spec.ts
│ └── package.json
├── examples
├── next
│ ├── .gitignore
│ ├── readme.md
│ ├── package.json
│ ├── pages
│ │ └── index.js
│ └── package-lock.json
├── parcel
│ ├── .gitignore
│ ├── package.json
│ ├── readme.md
│ ├── index.html
│ ├── index.js
│ └── package-lock.json
├── react
│ ├── readme.md
│ ├── public
│ │ ├── favicon.ico
│ │ ├── manifest.json
│ │ └── index.html
│ ├── src
│ │ ├── index.js
│ │ └── App.js
│ ├── .gitignore
│ └── package.json
└── transports
│ ├── axios.js
│ ├── ky.js
│ ├── ky-universal.js
│ └── superagent.js
├── lerna.json
├── .gitignore
├── .prettierrc
├── .editorconfig
├── .github
├── renovate.json
├── pull_request_template.md
├── ISSUE_TEMPLATE
│ ├── Bug_report.md
│ └── Feature_request.md
├── issue_template.md
└── workflows
│ └── node.yml
├── docs
├── v3
│ └── readme.md
├── v1
│ └── readme.md
└── v2
│ └── readme.md
├── jest.config.js
├── .eslintrc
├── README.md
├── package.json
├── tsconfig.json
├── LICENSE
└── CONTRIBUTING.md
/.prettierignore:
--------------------------------------------------------------------------------
1 | packages/*/dist
2 |
--------------------------------------------------------------------------------
/packages/client/test/mocks/foo.txt:
--------------------------------------------------------------------------------
1 | hello world
--------------------------------------------------------------------------------
/examples/next/.gitignore:
--------------------------------------------------------------------------------
1 | .next
2 | out
3 | node_modules
4 |
--------------------------------------------------------------------------------
/examples/parcel/.gitignore:
--------------------------------------------------------------------------------
1 | .cache
2 | dist
3 | node_modules
4 |
--------------------------------------------------------------------------------
/packages/client/jest.setup.js:
--------------------------------------------------------------------------------
1 | require('isomorphic-fetch');
2 |
--------------------------------------------------------------------------------
/examples/next/readme.md:
--------------------------------------------------------------------------------
1 | # Next example
2 |
3 | 1. Run `npm install`
4 | 2. Run `npm run dev`
5 |
--------------------------------------------------------------------------------
/examples/react/readme.md:
--------------------------------------------------------------------------------
1 | # React example
2 |
3 | 1. Run `npm install`
4 | 2. Run `npm run start`
5 |
--------------------------------------------------------------------------------
/examples/react/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylletjs/yllet/HEAD/examples/react/public/favicon.ico
--------------------------------------------------------------------------------
/packages/client/README.md:
--------------------------------------------------------------------------------
1 | # yllet
2 |
3 | Please refer to its documentation [here](https://github.com/ylletjs/yllet).
4 |
--------------------------------------------------------------------------------
/packages/react/README.md:
--------------------------------------------------------------------------------
1 | # yllet-react
2 |
3 | Please refer to its documentation [here](https://github.com/ylletjs/yllet).
4 |
--------------------------------------------------------------------------------
/examples/parcel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "parcel-example",
3 | "dependencies": {
4 | "@yllet/client": "^3.0.1"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/parcel/readme.md:
--------------------------------------------------------------------------------
1 | # Parcel example
2 |
3 | 1. Run `npm install`
4 | 2. Run `npm install -g parcel-bundler`
5 | 3. Run `parcel index.html`
6 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*"
4 | ],
5 | "npmClient": "yarn",
6 | "useWorkspaces": true,
7 | "version": "3.0.2"
8 | }
9 |
--------------------------------------------------------------------------------
/packages/support/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | displayName: '@yllet/support',
3 | transform: {
4 | '^.+\\.ts?$': 'ts-jest',
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/packages/react/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | displayName: '@yllet/react',
3 | testEnvironment: 'jsdom',
4 | transform: {
5 | '^.+\\.tsx?$': 'ts-jest',
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/packages/react/src/index.ts:
--------------------------------------------------------------------------------
1 | export { Provider } from './provider';
2 | export { default as withClient } from './withClient';
3 | export { default as useClient } from './useClient';
4 |
--------------------------------------------------------------------------------
/examples/react/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/packages/support/README.md:
--------------------------------------------------------------------------------
1 | # `support`
2 |
3 | > TODO: description
4 |
5 | ## Usage
6 |
7 | ```
8 | const support = require('support');
9 |
10 | // TODO: DEMONSTRATE API
11 | ```
12 |
--------------------------------------------------------------------------------
/packages/support/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "dist",
5 | "rootDir": "src"
6 | },
7 | "exclude": ["dist", "test"]
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | node_modules
3 | packages/*/dist/
4 | packages/*/node_modules/
5 | .jest-*
6 | browserstack.err
7 | .DS_Store
8 | /index.js
9 | /test*
10 | /coverage
11 | tsconfig.tsbuildinfo
12 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "bracketSpacing": true,
4 | "singleQuote": true,
5 | "trailingComma": "all",
6 | "printWidth": 100,
7 | "tabWidth": 2,
8 | "semi": true
9 | }
10 |
--------------------------------------------------------------------------------
/packages/client/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | displayName: '@yllet/client',
3 | setupFilesAfterEnv: ['/jest.setup.js'],
4 | transform: {
5 | '^.+\\.ts?$': 'ts-jest',
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/packages/client/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { Options, Params, Next, Middleware } from './Client.types';
2 | export type { Transport } from './Transport.types';
3 | export { default as default } from './Client';
4 |
--------------------------------------------------------------------------------
/examples/parcel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Yllet demo
4 |
5 |
6 | Posts
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/packages/client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "dist",
5 | "rootDir": "src"
6 | },
7 | "exclude": ["dist", "test"],
8 | "references": [{ "path": "../support" }]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "dist",
5 | "rootDir": "src",
6 | "jsx": "react"
7 | },
8 | "exclude": ["dist", "test"],
9 | "references": [{ "path": "../client" }]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/client/src/Client.types.ts:
--------------------------------------------------------------------------------
1 | import Client from '.';
2 |
3 | export type Options = Record;
4 |
5 | export type Params = Record;
6 |
7 | export type Next = () => void;
8 |
9 | export type Middleware = (client: Client, next: Next) => void;
10 |
--------------------------------------------------------------------------------
/packages/react/src/provider.types.ts:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 | import Client from '@yllet/client';
3 | export interface ContextValue {
4 | client: Client | null;
5 | }
6 |
7 | export type ProviderProps = {
8 | client: Client;
9 | children: ReactNode;
10 | };
11 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ],
5 | "rangeStrategy": "bump",
6 | "automerge": true,
7 | "major": {
8 | "automerge": false
9 | },
10 | "minor": {
11 | "automerge": false
12 | },
13 | "separateMultipleMajor": true
14 | }
15 |
--------------------------------------------------------------------------------
/docs/v3/readme.md:
--------------------------------------------------------------------------------
1 | # Yllet docs v3
2 |
3 | Version 3 is a rewritten version of [version 2](../v2/readme.md) in TypeScript with a few changes.
4 | The documentation for [version 2](../v2/readme.md) still applies
5 |
6 | ## Changes
7 |
8 | - TypeScript types
9 | - `withClientData` function is removed
10 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | projects: ['/packages/*/jest.config.js'],
5 | testPathIgnorePatterns: ['/packages/(?:.+?)/dist/'],
6 | coveragePathIgnorePatterns: ['/packages/(?:.+?)/dist/'],
7 | coverageReporters: ['html', 'json', 'lcov', 'text', 'clover']
8 | };
9 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
6 |
7 | ### Description
8 |
9 | (please provide us with clear instructions on how you verified your changes work)
10 |
11 | ### Checklist
12 |
13 | - [ ] Bug fix?
14 | - [ ] New feature?
15 | - [ ] Deprecations?
16 | - [ ] Created tests, if possible
17 |
--------------------------------------------------------------------------------
/packages/react/src/provider.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import type { ContextValue, ProviderProps } from './provider.types';
3 |
4 | export const Context = React.createContext({ client: null });
5 |
6 | export const Provider = ({ client, children }: ProviderProps) => (
7 | {children}
8 | );
9 |
--------------------------------------------------------------------------------
/packages/react/src/withClient.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { Context } from './provider';
3 |
4 | const withClient =
5 | (Component: React.ComponentType) =>
6 | ({ ...props }) => {
7 | const context = useContext(Context);
8 | props.client = context.client;
9 | return ;
10 | };
11 |
12 | export default withClient;
13 |
--------------------------------------------------------------------------------
/examples/parcel/index.js:
--------------------------------------------------------------------------------
1 | import Client from '@yllet/client';
2 |
3 | const list = document.getElementById('posts');
4 |
5 | const client = new Client({
6 | endpoint: 'http://wordpress.test/wp-json/'
7 | });
8 |
9 | client
10 | .posts()
11 | .get()
12 | .then((res) => {
13 | res.forEach((p) => {
14 | list.innerHTML += '' + p.title.rendered + '';
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/examples/react/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/examples/next/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@yllet/react": "^3.0.1",
7 | "next": "^12.1.0",
8 | "react": "^17.0.2",
9 | "react-dom": "^17.0.2"
10 | },
11 | "scripts": {
12 | "export": "next export",
13 | "start": "next start",
14 | "build": "next build",
15 | "dev": "next"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/react/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/packages/client/src/Transport.types.ts:
--------------------------------------------------------------------------------
1 | export interface Transport {
2 | delete(url: string, data: Record | undefined, config: Record): any;
3 | get(url: string, data: Record | undefined, config: Record): any;
4 | post(url: string, data: Record | undefined, config: Record): any;
5 | put(url: string, data: Record | undefined, config: Record): any;
6 | }
7 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "env": {
4 | "node": true
5 | },
6 | "parser": "@typescript-eslint/parser",
7 | "plugins": ["@typescript-eslint"],
8 | "extends": [
9 | "eslint:recommended",
10 | "plugin:@typescript-eslint/eslint-recommended",
11 | "plugin:@typescript-eslint/recommended"
12 | ],
13 | "rules": {
14 | "@typescript-eslint/ban-ts-comment": 0,
15 | "@typescript-eslint/explicit-module-boundary-types": 0,
16 | "@typescript-eslint/no-explicit-any": 0
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/support/src/HTTPError.ts:
--------------------------------------------------------------------------------
1 | export default class HTTPError extends Error {
2 | /**
3 | * Name of the error.
4 | *
5 | * @var {string}
6 | */
7 | name: string;
8 |
9 | /**
10 | * The response.
11 | *
12 | * @var {object}
13 | */
14 | response: Record;
15 |
16 | /**
17 | * HTTPError constructor.
18 | *
19 | * @param {object} response
20 | */
21 | constructor(response: Record) {
22 | super(response.statusText);
23 | this.name = 'HTTPError';
24 | this.response = response;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/react/src/useClient.ts:
--------------------------------------------------------------------------------
1 | import Client from '@yllet/client';
2 | import type { Options } from '@yllet/client';
3 | import { useMemo, useContext } from 'react';
4 | import { Context } from './provider';
5 |
6 | /**
7 | * Use client creates a new client.
8 | *
9 | * @param {object} options
10 | */
11 | const useClient = (options: string | Options = {}) => {
12 | const context = useContext(Context);
13 |
14 | if (context.client) {
15 | return context.client;
16 | }
17 |
18 | return useMemo(() => new Client(options), []);
19 | };
20 |
21 | export default useClient;
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/Bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | ### What I expected
8 |
9 | (write your answer here)
10 |
11 | ### What happened instead
12 |
13 | (write your answer here)
14 |
15 | ### Steps to reproduce
16 |
17 | (write your steps here:)
18 |
19 | 1.
20 | 2.
21 | 3.
22 |
23 | ### Environment
24 |
25 | 1. `node -v`:
26 | 2. `npm -v`:
27 | 3. `yarn --version` (if you use Yarn):
28 |
29 | Then, specify:
30 |
31 | 1. Operating system:
32 | 2. Browser and version (if relevant):
33 |
--------------------------------------------------------------------------------
/packages/react/test/withClient.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Client from '@yllet/client'
3 | import { render } from '@testing-library/react';
4 | import { Provider, withClient } from '../src';
5 |
6 | const Foo = ({ client }:any) => {client.options.endpoint};
7 |
8 | test('withClient', async () => {
9 | const endpoint = 'http://wordpress.test/wp-json';
10 | const client = new Client({ endpoint });
11 | const Connected = withClient(Foo);
12 | const wrapper = render(
13 |
14 |
15 |
16 | );
17 | expect(wrapper.getByText(endpoint)).not.toBeUndefined();
18 | });
19 |
--------------------------------------------------------------------------------
/packages/react/test/useClient.spec.tsx:
--------------------------------------------------------------------------------
1 | import { renderHook } from '@testing-library/react-hooks'
2 | import { useClient } from '../src';
3 |
4 | describe('useClient', () => {
5 | it('test useClient', () => {
6 | const endpoint = 'https://demo.wp-api.org/wp-json';
7 | const { result } = renderHook(() => useClient({ endpoint }));
8 | expect(result.current.options.endpoint).toBe(endpoint);
9 | });
10 |
11 | it('test useClient with string', () => {
12 | const endpoint = 'https://demo.wp-api.org/wp-json';
13 | const { result } = renderHook(() => useClient(endpoint));
14 | expect(result.current.options.endpoint).toBe(endpoint);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/Feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/packages/client/test/mocks/MockTransport.ts:
--------------------------------------------------------------------------------
1 | import 'core-js/features/promise';
2 | import { fn } from 'jest-mock';
3 |
4 | export default class MockTransport {
5 | responses: Record = {};
6 |
7 | constructor(responses = {}) {
8 | this.responses = responses;
9 | this.resetMocks();
10 | }
11 |
12 | resetMocks() {
13 | ['post', 'get', 'put', 'delete'].forEach((verb) => {
14 | this[verb] = fn((url, data, config) => this.request(verb));
15 | });
16 | }
17 |
18 | request(verb: string) {
19 | return new Promise((resolve, reject) => {
20 | if (this.responses[verb]) {
21 | resolve(this.responses[verb]);
22 | }
23 | });
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 |
10 |
11 | ### What I expected
12 |
13 | (write your answer here)
14 |
15 | ### What happened instead
16 |
17 | (write your answer here)
18 |
19 | ### Steps to reproduce
20 |
21 | (write your steps here:)
22 |
23 | 1.
24 | 2.
25 | 3.
26 |
27 | ### Environment
28 |
29 | 1. `node -v`:
30 | 2. `npm -v`:
31 | 3. `yarn --version` (if you use Yarn):
32 |
33 | Then, specify:
34 |
35 | 1. Operating system:
36 | 2. Browser and version (if relevant):
37 |
--------------------------------------------------------------------------------
/packages/client/test/namespace.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Client from '../src';
3 | import MockTransport from './mocks/MockTransport';
4 |
5 | const transport = new MockTransport();
6 | const endpoint = 'http://wordpress.test/wp-json';
7 | const client = new Client({ transport, endpoint });
8 |
9 | describe('Client.namespace', () => {
10 | beforeEach(() => {
11 | transport.resetMocks();
12 | });
13 |
14 | it('sets the current namespace', () => {
15 | client.namespace('wc/v1');
16 | expect(client.options.namespace).toBe('wc/v1');
17 | });
18 |
19 | it('has fluent interface', () => {
20 | const returnValue = client.namespace('wc/v1');
21 | expect(returnValue).toBe(client);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/client/test/resource.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Client from '../src';
3 | import MockTransport from './mocks/MockTransport';
4 |
5 | const transport = new MockTransport();
6 | const endpoint = 'http://wordpress.test/wp-json';
7 | const client = new Client({ transport, endpoint });
8 |
9 | describe('Client.resource', () => {
10 | beforeEach(() => {
11 | transport.resetMocks();
12 | });
13 |
14 | it('sets the current path', () => {
15 | client.resource('products');
16 | expect(client.options.resource).toBe('products');
17 | });
18 |
19 | it('has fluent interface', () => {
20 | const returnValue = client.resource('products');
21 | expect(returnValue).toBe(client);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/.github/workflows/node.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 |
6 | # Run tests for any PRs.
7 | pull_request:
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [12.x, 14.x, 16.x]
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v3.7.0
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | - name: yarn install
24 | run: yarn install
25 | - name: yarn lint
26 | run: yarn lint
27 | - name: yarn build
28 | run: yarn build
29 | - name: yarn test
30 | run: yarn test
31 | env:
32 | CI: true
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Yllet
2 |
3 | [](https://github.com/ylletjs/yllet/actions)
4 | 
5 | 
6 |
7 |
8 | ## Docs
9 |
10 | - [Version 1](docs/v1)
11 | - [Version 2](docs/v2)
12 | - [Version 3](docs/v3)
13 |
14 | ## Contributing
15 |
16 | We'd love to have your helping hand on yllet! See [CONTRIBUTING.md](https://github.com/ylletjs/yllet/blob/master/CONTRIBUTING.md) for more information.
17 |
18 | ## License
19 |
20 | MIT © [Fredrik Forsmo](https://github.com/frozzare)
21 |
--------------------------------------------------------------------------------
/examples/next/pages/index.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { useClient } from '@yllet/react';
3 |
4 | export default () => {
5 | const endpoint = 'http://wordpress.test/wp-json/';
6 | const client = useClient({ endpoint });
7 | const [posts, setPosts] = useState([]);
8 |
9 | useEffect(() => {
10 | const fetchPosts = async () => {
11 | const response = await client.posts().get();
12 | setPosts(response);
13 | };
14 |
15 | fetchPosts();
16 | }, [client]);
17 |
18 | return (
19 |
20 |
Posts
21 | {!posts.length &&
Loading...
}
22 |
23 | {posts.map((p, pi) => (
24 | - {p.title.rendered}
25 | ))}
26 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/examples/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@yllet/react": "^3.0.1",
7 | "react": "^17.0.2",
8 | "react-dom": "^17.0.2",
9 | "react-scripts": "^4.0.3"
10 | },
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test",
15 | "eject": "react-scripts eject"
16 | },
17 | "eslintConfig": {
18 | "extends": "react-app"
19 | },
20 | "browserslist": {
21 | "production": [
22 | ">0.2%",
23 | "not dead",
24 | "not op_mini all"
25 | ],
26 | "development": [
27 | "last 1 chrome version",
28 | "last 1 firefox version",
29 | "last 1 safari version"
30 | ]
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/examples/react/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { useClient } from '@yllet/react';
3 |
4 | function App() {
5 | const endpoint = 'http://wordpress.test/wp-json/';
6 | const client = useClient({ endpoint });
7 | const [posts, setPosts] = useState([]);
8 |
9 | useEffect(() => {
10 | const fetchPosts = async () => {
11 | const response = await client.posts().get();
12 | setPosts(response);
13 | };
14 |
15 | fetchPosts();
16 | }, [client]);
17 |
18 | return (
19 |
20 |
Posts
21 | {!posts.length &&
Loading...
}
22 |
23 | {posts.map((p, pi) => (
24 | - {p.title.rendered}
25 | ))}
26 |
27 |
28 | );
29 | }
30 |
31 | export default App;
32 |
--------------------------------------------------------------------------------
/packages/client/test/embed.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Client from '../src';
3 | import MockTransport from './mocks/MockTransport';
4 |
5 | const transport = new MockTransport();
6 | const endpoint = 'http://wordpress.test/wp-json';
7 | const client = new Client({ transport, endpoint });
8 |
9 | const params = {
10 | title: 'Hello World',
11 | content: 'Welcome to the Wordpress API'
12 | };
13 |
14 | describe('Client.embed', () => {
15 | it('can enable embed mode', () => {
16 | client.embed().request('get', params);
17 | expect((transport as any).get.mock.calls[0][1]).toEqual({
18 | _embed: true,
19 | ...params
20 | });
21 | });
22 |
23 | // it('has fluent interface', () => {
24 | // const returnValue = client.embed();
25 | // expect(returnValue).toBe(client);
26 | // });
27 | });
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yllet",
3 | "private": true,
4 | "workspaces": [
5 | "packages/*"
6 | ],
7 | "devDependencies": {
8 | "@types/jest": "^28.1.8",
9 | "@typescript-eslint/eslint-plugin": "^6.0.0",
10 | "@typescript-eslint/parser": "^6.0.0",
11 | "eslint": "^8.44.0",
12 | "isomorphic-fetch": "^3.0.0",
13 | "jest": "^28.1.3",
14 | "jest-mock": "28.1.3",
15 | "lerna": "^4.0.0",
16 | "prettier": "^2.8.8",
17 | "rimraf": "^3.0.2",
18 | "ts-jest": "^28.0.8",
19 | "typescript": "^4.9.5"
20 | },
21 | "scripts": {
22 | "bootstrap": "lerna bootstrap --use-workspaces",
23 | "build": "lerna run build",
24 | "start": "lerna run start",
25 | "test": "jest packages/**",
26 | "postinstall": "lerna bootstrap",
27 | "lint": "eslint packages/**/src --ext .ts",
28 | "format": "prettier --write 'packages/**/src/**/*.ts*' packages/**/test/**/*.ts*"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2020",
4 | "lib": ["es2020", "dom"],
5 | "allowJs": false,
6 | "declaration": true,
7 | "emitDeclarationOnly": false,
8 | "outDir": "dist/types",
9 | "rootDirs": ["src"],
10 | "noEmit": false,
11 | "strict": true,
12 | "moduleResolution": "node",
13 | "allowSyntheticDefaultImports": true,
14 | "esModuleInterop": true,
15 | "experimentalDecorators": true,
16 | "emitDecoratorMetadata": true,
17 | "skipLibCheck": true,
18 | "baseUrl": "src",
19 | "forceConsistentCasingInFileNames": true,
20 | "noImplicitReturns": true,
21 | "suppressImplicitAnyIndexErrors": true,
22 | "noUnusedLocals": true,
23 | "composite": true
24 | },
25 | "exclude": ["packages/**/test/**", "packages/**/dist/**"],
26 | "references": [
27 | { "path": "./packages/client" },
28 | { "path": "./packages/react" },
29 | { "path": "./packages/support" }
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/examples/transports/axios.js:
--------------------------------------------------------------------------------
1 | import AxiosClient from 'axios';
2 | import FormData from 'isomorphic-form-data';
3 |
4 | class AxiosTransport {
5 | axios = undefined;
6 |
7 | constructor(axios) {
8 | this.axios = typeof axios === 'undefined' ? AxiosClient : axios;
9 |
10 | ['post', 'get', 'put', 'delete'].forEach((verb) => {
11 | this[verb] = (url, data, config) => this.request(verb, url, data, config);
12 | });
13 | }
14 |
15 | request(verb, url, data, config = {}) {
16 | const request = {
17 | ...config,
18 | url,
19 | method: verb.toUpperCase()
20 | };
21 |
22 | if (['PUT', 'POST'].includes(verb.toUpperCase())) {
23 | request.data = data;
24 | } else {
25 | if (data instanceof FormData) {
26 | throw new TypeError(
27 | 'Unable to encode FormData for GET, DELETE requests'
28 | );
29 | }
30 | request.params = data;
31 | }
32 |
33 | return this.axios(request).then((response) => response.data);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/client/test/HTTPMethods.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Client from '../src';
3 | import MockTransport from './mocks/MockTransport';
4 |
5 | const METHODS = {
6 | get: 'get',
7 | create: 'post',
8 | update: 'put',
9 | delete: 'delete'
10 | };
11 |
12 | describe('Client.METHODS', () => {
13 | Object.keys(METHODS).forEach((method) => {
14 | const verb = METHODS[method];
15 | it(`"${method}" calls correct HTTP verb on transport`, () => {
16 | const transport = new MockTransport();
17 | const client = new Client({
18 | endpoint: 'http://wordpress.test/wp-json/',
19 | transport
20 | });
21 | client[method]('products', { foo: 'bar' });
22 | expect((transport[verb] as any).mock.calls.length).toBe(1);
23 | expect((transport[verb] as any).mock.calls[0][0]).toBe(
24 | 'http://wordpress.test/wp-json/wp/v2/products'
25 | );
26 | expect((transport[verb] as any).mock.calls[0][1]).toEqual({ foo: 'bar' });
27 | });
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/packages/support/test/HTTPError.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { HTTPError } from '../src';
3 |
4 | describe('HTTPError', () => {
5 | it('has error message', () => {
6 | const response = {
7 | status: 422,
8 | statusText: 'Invalid input data'
9 | };
10 | const error = new HTTPError(response);
11 | expect(error.message).toBe('Invalid input data');
12 | });
13 |
14 | it('has correct name', () => {
15 | const response = {
16 | status: 422,
17 | statusText: 'Invalid input data'
18 | };
19 | const error = new HTTPError(response);
20 | expect(error.name).toBe('HTTPError');
21 | });
22 |
23 | it('assigns response as property', () => {
24 | const response = {
25 | status: 422,
26 | statusText: 'Invalid input data'
27 | };
28 | const error = new HTTPError(response);
29 | expect(error.response).toEqual(response);
30 | expect(error.response.status).toBe(response.status);
31 | expect(error.response.statusText).toBe(response.statusText);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/packages/client/test/slug.spec.ts:
--------------------------------------------------------------------------------
1 | import Client from '../src';
2 | import MockTransport from './mocks/MockTransport';
3 | import expect from 'expect';
4 |
5 | const responses = {
6 | get: {
7 | posts: [
8 | { id: 1, title: 'post-1' },
9 | { id: 2, title: 'post-2' },
10 | { id: 3, title: 'post-3' }
11 | ]
12 | }
13 | };
14 |
15 | const transport = new MockTransport(responses);
16 | const endpoint = 'http://wordpress.test/wp-json';
17 | const client = new Client({ transport, endpoint });
18 |
19 | describe('Client.slug', () => {
20 | it('return first post', async () => {
21 | await client.posts().slug('about');
22 | expect((transport as any).get.mock.calls[0][0]).toBe(
23 | `${endpoint}/wp/v2/posts`
24 | );
25 | });
26 |
27 | it('has the right params', async () => {
28 | await client.posts().slug('about', {
29 | search: 'search'
30 | });
31 | expect((transport as any).get.mock.calls[1][1]).toEqual({
32 | search: 'search',
33 | per_page: 1,
34 | slug: 'about'
35 | });
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/packages/client/test/param.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Client from '../src';
3 | import MockTransport from './mocks/MockTransport';
4 |
5 | const transport = new MockTransport();
6 | const endpoint = 'http://wordpress.test/wp-json';
7 | const client = new Client({ transport, endpoint });
8 |
9 | describe('Client.resource', () => {
10 | beforeEach(() => {
11 | transport.resetMocks();
12 | });
13 |
14 | it('can return a param', () => {
15 | client.params.foo = 'bar';
16 | expect(client.param('foo')).toBe('bar');
17 | });
18 |
19 | it('can set a param', () => {
20 | client.param('test', 'foo');
21 | expect(client.params.test).toBe('foo');
22 | });
23 |
24 | it('can set a param object', () => {
25 | client.param({ a: '1', b: '2' });
26 | expect(client.params).toEqual({
27 | foo: 'bar',
28 | test: 'foo',
29 | a: '1',
30 | b: '2'
31 | });
32 | });
33 |
34 | it('has fluent interface', () => {
35 | const returnValue = client.param({ a: '1', b: '2' });
36 | expect(returnValue).toBe(client);
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/packages/client/test/header.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Client from '../src';
3 | import MockTransport from './mocks/MockTransport';
4 |
5 | const transport = new MockTransport();
6 | const endpoint = 'http://wordpress.test/wp-json';
7 | const client = new Client({ transport, endpoint });
8 |
9 | describe('Client.header', () => {
10 | beforeEach(() => {
11 | transport.resetMocks();
12 | });
13 |
14 | it('set a single header', () => {
15 | client.header('X-Foo', 'bar');
16 | expect(client.options.config.headers['X-Foo']).toBe('bar');
17 | });
18 |
19 | it('can return headers', () => {
20 | expect(client.header('X-Foo')).toBe('bar');
21 | });
22 |
23 | it('set a headers object', () => {
24 | client.header({ 'X-Foo': '1', 'X-Bar': '2' });
25 | expect(client.options.config.headers).toEqual({
26 | 'Content-Type': 'application/json',
27 | 'X-Foo': '1',
28 | 'X-Bar': '2'
29 | });
30 | });
31 |
32 | it('has fluent interface', () => {
33 | const returnValue = client.header('X-Foo', 'bar');
34 | expect(returnValue).toBe(client);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Fredrik Forsmo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/examples/transports/ky.js:
--------------------------------------------------------------------------------
1 | import { qsEncode } from '@yllet/support';
2 | import KyClient from 'ky';
3 | import FormData from 'isomorphic-form-data';
4 |
5 | class KyTransport {
6 | constructor(ky) {
7 | this.ky = typeof ky === 'undefined' ? KyClient : ky;
8 | ['post', 'get', 'put', 'delete'].forEach((verb) => {
9 | this[verb] = (url, data, config) => this.request(verb, url, data, config);
10 | });
11 | }
12 |
13 | async request(verb, url, data, config = {}) {
14 | const request = {
15 | ...config,
16 | method: verb.toUpperCase()
17 | };
18 |
19 | if (data) {
20 | if (['PUT', 'POST'].includes(verb.toUpperCase())) {
21 | request.body = data instanceof FormData ? data : JSON.stringify(data);
22 | } else {
23 | if (data instanceof FormData) {
24 | throw new TypeError(
25 | 'Unable to encode FormData for GET, DELETE requests'
26 | );
27 | }
28 |
29 | const qs = qsEncode(data);
30 |
31 | if (qs.length) {
32 | url = `${url}?${qs}`;
33 | }
34 | }
35 | }
36 |
37 | return await this.ky(url, request).json();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/transports/ky-universal.js:
--------------------------------------------------------------------------------
1 | import { qsEncode } from '@yllet/support';
2 | import KyClient from 'ky-universal';
3 | import FormData from 'isomorphic-form-data';
4 |
5 | class KyTransport {
6 | constructor(ky) {
7 | this.ky = typeof ky === 'undefined' ? KyClient : ky;
8 | ['post', 'get', 'put', 'delete'].forEach((verb) => {
9 | this[verb] = (url, data, config) => this.request(verb, url, data, config);
10 | });
11 | }
12 |
13 | async request(verb, url, data, config = {}) {
14 | const request = {
15 | ...config,
16 | method: verb.toUpperCase()
17 | };
18 |
19 | if (data) {
20 | if (['PUT', 'POST'].includes(verb.toUpperCase())) {
21 | request.body = data instanceof FormData ? data : JSON.stringify(data);
22 | } else {
23 | if (data instanceof FormData) {
24 | throw new TypeError(
25 | 'Unable to encode FormData for GET, DELETE requests'
26 | );
27 | }
28 |
29 | const qs = qsEncode(data);
30 |
31 | if (qs.length) {
32 | url = `${url}?${qs}`;
33 | }
34 | }
35 | }
36 |
37 | return await this.ky(url, request).json();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/support/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@yllet/support",
3 | "private": false,
4 | "version": "3.0.1",
5 | "repository": "ylletjs/yllet",
6 | "description": "Support package for Yllet",
7 | "author": "Fredrik Forsmo ",
8 | "homepage": "https://github.com/ylletjs/yllet#readme",
9 | "license": "MIT",
10 | "main": "dist/cjs/index.js",
11 | "module": "dist/esm/index.js",
12 | "types": "dist/types",
13 | "files": [
14 | "README.md",
15 | "dist/"
16 | ],
17 | "scripts": {
18 | "prebuild": "rimraf dist",
19 | "build": "yarn build:cjs && yarn build:esm && yarn build:types",
20 | "build:cjs": "tsc --target es5 --module commonjs --outDir dist/cjs",
21 | "build:esm": "tsc --target es2020 --module es2020 --outDir dist/esm",
22 | "build:types": "tsc --target es2020 --module es2020 --outDir dist/types --emitDeclarationOnly",
23 | "postbuild": "rimraf dist/cjs/*.d.ts dist/esm/*.d.ts",
24 | "preversion": "yarn run build"
25 | },
26 | "bugs": {
27 | "url": "https://github.com/ylletjs/yllet/issues"
28 | },
29 | "gitHead": "a2a2a3d8db1a79d619928f935f18c1bd05c8622d",
30 | "publishConfig": {
31 | "access": "public"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/examples/transports/superagent.js:
--------------------------------------------------------------------------------
1 | import SuperagentClient from 'superagent';
2 |
3 | class SuperagentTransport {
4 | constructor(superagent) {
5 | this.superagent =
6 | typeof superagent === 'undefined' ? SuperagentClient : superagent;
7 |
8 | ['post', 'get', 'put', 'delete'].forEach((verb) => {
9 | this[verb] = (url, data, config) => this.request(verb, url, data, config);
10 | });
11 | }
12 |
13 | async request(verb, url, data, config = {}) {
14 | let request = this.superagent[verb](url);
15 |
16 | if (data) {
17 | if (['PUT', 'POST'].includes(verb.toUpperCase())) {
18 | request = request.send(
19 | data instanceof FormData ? data : JSON.stringify(data)
20 | );
21 | } else {
22 | if (data instanceof FormData) {
23 | throw new TypeError(
24 | 'Unable to encode FormData for GET, DELETE requests'
25 | );
26 | }
27 |
28 | request = request.query(data);
29 | }
30 | }
31 |
32 | Object.keys(config.headers).forEach((key) => {
33 | request = request.set(key, config.headers[key]);
34 | });
35 |
36 | return request.then((res) => {
37 | return JSON.parse(res.text);
38 | });
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/client/test/discover.spec.ts:
--------------------------------------------------------------------------------
1 | import Client from '../src';
2 | import MockTransport from './mocks/MockTransport';
3 | import expect from 'expect';
4 |
5 | describe('Client.discover', () => {
6 | it('requests discovery route', () => {
7 | const transport = new MockTransport();
8 | const client = new Client({ transport });
9 | client.discover('http://demo.wp-api.org');
10 | expect((transport as any).get.mock.calls[0][0]).toBe(
11 | 'http://demo.wp-api.org'
12 | );
13 | expect((transport as any).get.mock.calls[0][1]).toEqual({
14 | rest_route: '/'
15 | });
16 | });
17 |
18 | it('returns api route', () => {
19 | const transport = new MockTransport({
20 | get: {
21 | routes: {
22 | '/': {
23 | _links: {
24 | self: 'http://demo.wp-api.org/wp-json/'
25 | }
26 | }
27 | }
28 | }
29 | });
30 | const client = new Client({ transport });
31 | client
32 | .discover('http://demo.wp-api.org')
33 | .then((response) =>
34 | expect(response).toBe('http://demo.wp-api.org/wp-json/')
35 | );
36 | });
37 |
38 | it('throws Error', () => {
39 | const transport = new MockTransport({
40 | get: {}
41 | });
42 | const client = new Client({ transport });
43 | client.discover('http://demo.wp-api.org').catch((error) => {
44 | expect(error instanceof Error).toBe(true);
45 | expect(error.message).toBe('Unable to find the REST API');
46 | });
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/packages/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@yllet/client",
3 | "private": false,
4 | "version": "3.0.1",
5 | "repository": "ylletjs/yllet",
6 | "description": "JavaScript client for the WordPress REST API",
7 | "author": "Fredrik Forsmo ",
8 | "keywords": [
9 | "wordpress",
10 | "rest",
11 | "api",
12 | "client",
13 | "isomorphic",
14 | "headless"
15 | ],
16 | "main": "dist/cjs/index.js",
17 | "module": "dist/esm/index.js",
18 | "types": "dist/types",
19 | "files": [
20 | "README.md",
21 | "dist/"
22 | ],
23 | "bugs": {
24 | "url": "https://github.com/ylletjs/yllet/issues"
25 | },
26 | "scripts": {
27 | "prebuild": "rimraf dist",
28 | "build": "yarn build:cjs && yarn build:esm && yarn build:types",
29 | "build:cjs": "tsc --target es5 --module commonjs --outDir dist/cjs && echo \"module.exports = exports.default;\" >> dist/cjs/index.js",
30 | "build:esm": "tsc --target es2020 --module es2020 --outDir dist/esm",
31 | "build:types": "tsc --target es2020 --module es2020 --outDir dist/types --emitDeclarationOnly",
32 | "postbuild": "rimraf dist/cjs/*.d.ts dist/esm/*.d.ts",
33 | "preversion": "yarn run build"
34 | },
35 | "dependencies": {
36 | "@yllet/support": "^3.0.1",
37 | "isomorphic-form-data": "^2.0.0"
38 | },
39 | "license": "MIT",
40 | "devDependencies": {
41 | "@types/isomorphic-form-data": "2.0.1",
42 | "fetch-mock": "^9.11.0"
43 | },
44 | "gitHead": "a2a2a3d8db1a79d619928f935f18c1bd05c8622d",
45 | "publishConfig": {
46 | "access": "public"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/client/test/file.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import fs from 'fs';
3 | import Client from '../src';
4 | import FormData from 'isomorphic-form-data';
5 | import MockTransport from './mocks/MockTransport';
6 |
7 | const transport = new MockTransport();
8 | const endpoint = 'http://wordpress.test/wp-json';
9 | const client = new Client({ transport, endpoint });
10 |
11 | const isFsAvailable = typeof fs.createReadStream === 'function';
12 |
13 | const isRunningInBrowser = Boolean(process.env.BROWSER_ENV);
14 |
15 | function runTests(file: any) {
16 | describe('Client.file', () => {
17 | beforeEach(() => {
18 | transport.resetMocks();
19 | });
20 |
21 | it('can attach file from argument', () => {
22 | client.file(file, 'foo.txt');
23 | expect(client.formData instanceof FormData).toBe(true);
24 | });
25 |
26 | it('adds correct headers to request', () => {
27 | client.file(file, 'foo.txt');
28 | expect(client.options.config.headers['Content-Type']).toBe(
29 | 'multipart/form-data'
30 | );
31 | expect(client.options.config.headers['Content-Disposition']).toMatch(
32 | /attachment; filename=foo.txt/
33 | );
34 | });
35 |
36 | it('has fluent interface', () => {
37 | const returnValue = client.file(file, 'foo.txt');
38 | expect(returnValue).toBe(client);
39 | });
40 | });
41 | }
42 |
43 | // run tests
44 |
45 | if (isFsAvailable) {
46 | const file = fs.createReadStream(`${__dirname}/mocks/foo.txt`);
47 | runTests(file);
48 | }
49 |
50 | if (isRunningInBrowser) {
51 | var file = new Blob(['foo'], { type: 'text/plain' });
52 | runTests(file);
53 | }
54 |
--------------------------------------------------------------------------------
/examples/react/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | React App
23 |
24 |
25 |
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/packages/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@yllet/react",
3 | "private": false,
4 | "version": "3.0.2",
5 | "repository": "ylletjs/yllet",
6 | "description": "React bindings for Yllet",
7 | "author": "Fredrik Forsmo ",
8 | "keywords": [
9 | "wordpress",
10 | "rest",
11 | "api",
12 | "client",
13 | "react",
14 | "isomorphic",
15 | "headless"
16 | ],
17 | "main": "dist/cjs/index.js",
18 | "module": "dist/esm/index.js",
19 | "types": "dist/types",
20 | "files": [
21 | "README.md",
22 | "dist/"
23 | ],
24 | "bugs": {
25 | "url": "https://github.com/ylletjs/yllet/issues"
26 | },
27 | "scripts": {
28 | "prebuild": "rimraf dist",
29 | "build": "yarn build:cjs && yarn build:esm && yarn build:types",
30 | "build:cjs": "tsc --target es5 --module commonjs --outDir dist/cjs",
31 | "build:esm": "tsc --target es2020 --module es2020 --outDir dist/esm",
32 | "build:types": "tsc --target es2020 --module es2020 --outDir dist/types --emitDeclarationOnly",
33 | "postbuild": "rimraf dist/cjs/*.d.ts dist/esm/*.d.ts",
34 | "preversion": "yarn run build"
35 | },
36 | "peerDependencies": {
37 | "react": "*"
38 | },
39 | "dependencies": {
40 | "@yllet/client": "^3.0.1",
41 | "invariant": "^2.2.4",
42 | "prop-types": "^15.8.1"
43 | },
44 | "devDependencies": {
45 | "@testing-library/jest-dom": "^5.16.5",
46 | "@testing-library/react": "^13.4.0",
47 | "@testing-library/react-hooks": "^8.0.1",
48 | "@types/invariant": "2.2.35",
49 | "jest-environment-jsdom": "^28.1.3",
50 | "@types/react": "^18.2.17",
51 | "react": "^18.2.0",
52 | "react-dom": "^18.2.0"
53 | },
54 | "license": "MIT",
55 | "gitHead": "a2a2a3d8db1a79d619928f935f18c1bd05c8622d",
56 | "publishConfig": {
57 | "access": "public"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Yllet
2 |
3 | Everyone is welcome to contribute with patches, bug-fixes and new features. This is and will always be a community driven project.
4 |
5 | ## Core Ideas
6 |
7 | The purpose of Yllet is to create a easy WordPress REST API client that works with both React and non-React project. If a third party plugin works with the REST API it then it will work with Yllet.
8 |
9 | This project will never add plugin specific support since it's goal is to support the WordPress REST API.
10 |
11 | ## Submitting a Pull Request
12 |
13 | Good pull requests with patches, improvements or new features is always welcome. They should remain focused in scope and avoid containing unrelated commits.
14 |
15 | Please follow the projects code style and try to add tests for your changes.
16 |
17 | * Fork [ylletjs/ylelt](https://github.com/ylletjs/yllet) on Github and add the upstream remote.
18 |
19 | ```
20 | git clone https://github.com//yllet.git
21 | cd yllet
22 | git remote add upstream https://github.com/ylletjs/yllet.git
23 | ```
24 |
25 | This is useful if you cloned your repo a while ago and now wants to update it.
26 |
27 | ```
28 | git checkout master
29 | git pull upstream master
30 | ```
31 |
32 | * Create a new branch:
33 |
34 | ```
35 | git checkout -b
36 | ```
37 |
38 | * Make sure to update, or add to the tests when appropriate.
39 | * Commit your changes to your fork.
40 | * Locally merge (or rebase) the upstream development branch into your topic branch:
41 |
42 | ```
43 | git pull [--rebase] upstream master
44 | ```
45 |
46 | * Push to your branch:
47 |
48 | ```
49 | git push origin
50 | ```
51 |
52 | * [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `master` branch.
53 |
54 | **Note:**
55 | If you are making several changes at once please divide them into multiple pull requests.
56 |
57 | ## Folder Structure
58 |
59 | Yllet it's a monorepo containg all packages. These packages can be found in the [`packages/`](https://github.com/ylletjs/yllet/tree/master/packages) directory.
60 |
61 | ## License
62 |
63 | By contributing your code, you agree to license your contribution under the [MIT license](https://github.com/ylletjs/yllet/blob/master/LICENSE).
64 |
--------------------------------------------------------------------------------
/packages/client/test/request.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Client from '../src';
3 | import FormData from 'isomorphic-form-data';
4 | import MockTransport from './mocks/MockTransport';
5 |
6 | const transport = new MockTransport();
7 | const endpoint = 'http://wordpress.test/wp-json';
8 | const client = new Client({ transport, endpoint });
9 |
10 | const params = {
11 | title: 'Hello World',
12 | content: 'Welcome to the Wordpress API'
13 | };
14 |
15 | describe('Client.request', () => {
16 | beforeEach(() => {
17 | transport.resetMocks();
18 | });
19 |
20 | it('accepts path as 2nd param', () => {
21 | client.request('post', 'products');
22 | expect((transport as any).post.mock.calls[0][0]).toBe(
23 | `${endpoint}/wp/v2/products`
24 | );
25 | });
26 |
27 | it('accepts params as 2nd param', () => {
28 | client.request('post', params);
29 | expect((transport as any).post.mock.calls[0][0]).toBe(`${endpoint}/wp/v2`);
30 | expect((transport as any).post.mock.calls[0][1]).toEqual(params);
31 | });
32 |
33 | it('handles invalid paths', () => {
34 | client.request('post', undefined as any);
35 | expect((transport as any).post.mock.calls[0][0]).toBe(`${endpoint}/wp/v2`);
36 | client.request('post', 123 as any);
37 | expect((transport as any).post.mock.calls[1][0]).toBe(
38 | `${endpoint}/wp/v2/123`
39 | );
40 | client.request('post', null as any);
41 | expect((transport as any).post.mock.calls[2][0]).toBe(`${endpoint}/wp/v2`);
42 | client.request('post', {});
43 | expect((transport as any).post.mock.calls[3][0]).toBe(`${endpoint}/wp/v2`);
44 | client.request('post', 'products/variations/123');
45 | expect((transport as any).post.mock.calls[4][0]).toBe(
46 | `${endpoint}/wp/v2/products/variations/123`
47 | );
48 | });
49 |
50 | it('makes verb lowercase', () => {
51 | client.request('POST', undefined as any);
52 | expect((transport as any).post.mock.calls[0][0]).toBe(`${endpoint}/wp/v2`);
53 | });
54 |
55 | it('merges global params', () => {
56 | client.params = { a: '1', b: '2' };
57 | client.request('post', params);
58 | expect((transport as any).post.mock.calls[0][1]).toEqual({
59 | ...client.params,
60 | ...params
61 | });
62 | });
63 |
64 | it('converts request params to snake case', () => {
65 | client.params = { weLikeCamels: '1', andClimbingHills: '2' };
66 | client.request('post', { andGentleWavesLikeThis: '3' });
67 | expect((transport as any).post.mock.calls[0][1]).toEqual({
68 | weLikeCamels: '1',
69 | andClimbingHills: '2',
70 | and_gentle_waves_like_this: '3'
71 | });
72 | });
73 |
74 | it('can send a file', () => {
75 | const formData = new FormData();
76 | client.formData = formData;
77 | client.params = { a: '1', b: '2' };
78 | client.request('post', params);
79 |
80 | const result = (transport as any).post.mock.calls[0][1];
81 | expect(result instanceof FormData).toEqual(true);
82 | });
83 |
84 | it('merges global request config', () => {
85 | client.options.config = { a: '1', b: '2' };
86 | client.request('post');
87 | expect((transport as any).post.mock.calls[0][2]).toEqual({
88 | ...client.options.config
89 | });
90 | });
91 | });
92 |
--------------------------------------------------------------------------------
/packages/client/src/Transport.ts:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import { HTTPError, qsEncode } from '@yllet/support';
3 | import FormData from 'isomorphic-form-data';
4 | import type { Transport as ITransport } from './Transport.types';
5 | class Transport implements ITransport {
6 | /**
7 | * Send delete request.
8 | *
9 | * @param {string} url
10 | * @param {object} data
11 | * @param {object} config
12 | *
13 | * @return {object}
14 | */
15 | delete(
16 | url: string,
17 | data: Record | undefined = undefined,
18 | config: Record = {},
19 | ): any {
20 | return this.request('delete', url, data, config);
21 | }
22 |
23 | /**
24 | * Send get request.
25 | *
26 | * @param {string} url
27 | * @param {object} data
28 | * @param {object} config
29 | *
30 | * @return {object}
31 | */
32 | get(
33 | url: string,
34 | data: Record | undefined = undefined,
35 | config: Record = {},
36 | ): any {
37 | return this.request('get', url, data, config);
38 | }
39 |
40 | /**
41 | * Send post request.
42 | *
43 | * @param {string} url
44 | * @param {object} data
45 | * @param {object} config
46 | *
47 | * @return {object}
48 | */
49 | post(
50 | url: string,
51 | data: Record | undefined = undefined,
52 | config: Record = {},
53 | ): any {
54 | return this.request('post', url, data, config);
55 | }
56 |
57 | /**
58 | * Send put request.
59 | *
60 | * @param {string} url
61 | * @param {object} data
62 | * @param {object} config
63 | *
64 | * @return {object}
65 | */
66 | put(
67 | url: string,
68 | data: Record | undefined = undefined,
69 | config: Record = {},
70 | ): any {
71 | return this.request('put', url, data, config);
72 | }
73 |
74 | /**
75 | * Sned request against url with data.
76 | *
77 | * @param {string} verb
78 | * @param {string} url
79 | * @param {object} data
80 | * @param {object} config
81 | *
82 | * @return {object}
83 | */
84 | private request(
85 | verb: string,
86 | url: string,
87 | data: Record | undefined = undefined,
88 | config: Record = {},
89 | ): any {
90 | const request: RequestInit = {
91 | ...config,
92 | method: verb.toUpperCase(),
93 | };
94 |
95 | if (data) {
96 | if (['PUT', 'POST'].includes(verb.toUpperCase())) {
97 | request.body = data instanceof FormData ? (data as any) : JSON.stringify(data);
98 | } else {
99 | if (data instanceof FormData) {
100 | throw new TypeError('Unable to encode FormData for GET, DELETE requests');
101 | }
102 |
103 | const qs = qsEncode(data);
104 |
105 | if (qs.length) {
106 | url = `${url}?${qs}`;
107 | }
108 | }
109 | }
110 |
111 | return fetch(url, request).then((response) => {
112 | return response.json().then((data) => {
113 | if (!response.ok) {
114 | throw new HTTPError(data);
115 | }
116 |
117 | return data;
118 | });
119 | });
120 | }
121 | }
122 |
123 | export default Transport;
124 |
--------------------------------------------------------------------------------
/packages/support/src/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Export HTTPError.
3 | */
4 | export { default as HTTPError } from './HTTPError';
5 |
6 | /**
7 | * Test if given value is a object or not.
8 | *
9 | * @param {object} obj
10 | *
11 | * @return {bool}
12 | */
13 | export const isObject = (obj: any): boolean =>
14 | Object.prototype.toString.call(obj) === '[object Object]';
15 |
16 | /**
17 | * Convert camel case to snake case.
18 | *
19 | * @param {string} str
20 | *
21 | * @return {string}
22 | */
23 | const toSnakeCase = (str: string): string =>
24 | str
25 | .replace(/[\w]([A-Z])/g, function (m) {
26 | return m[0] + '_' + m[1];
27 | })
28 | .toLowerCase();
29 |
30 | /**
31 | * Convert object keys to snake case.
32 | *
33 | * @param {object} obj
34 | *
35 | * @return {object}
36 | */
37 | export const objectKeysToSnakeCase = (obj: Record): Record =>
38 | Object.keys(obj).reduce((previous, current) => {
39 | if (isObject(obj[current])) {
40 | obj[current] = objectKeysToSnakeCase(obj[current]);
41 | }
42 |
43 | if (obj[current] instanceof Array) {
44 | previous[toSnakeCase(current)] = obj[current].map(objectKeysToSnakeCase);
45 | } else {
46 | previous[toSnakeCase(current)] = obj[current];
47 | }
48 |
49 | return previous;
50 | }, {});
51 |
52 | /**
53 | * Flatten array.
54 | *
55 | * @param {array} list
56 | *
57 | * @return {array}
58 | */
59 | const flattenArray = (list: any[]): any[] =>
60 | list.reduce((a, b) => a.concat(Array.isArray(b) ? flattenArray(b) : b), []);
61 |
62 | /**
63 | * Encode objects as query strings.
64 | *
65 | * @param {object} params
66 | * @param {string} prefix
67 | *
68 | * @return {string}
69 | */
70 | export const qsEncode = (params: Record, prefix = ''): string =>
71 | Object.keys(params)
72 | .map((key) => {
73 | const isArray = params.constructor === Array;
74 | const value = isArray ? flattenArray(params)[key] : params[key];
75 |
76 | if (isArray) {
77 | key = `${prefix}[]`;
78 | } else if (params.constructor === Object) {
79 | key = prefix ? `${prefix}[${key}]` : key;
80 | }
81 |
82 | if (typeof value === 'object') {
83 | return qsEncode(value, key);
84 | }
85 |
86 | return `${key}=${encodeURIComponent(value)}`;
87 | })
88 | .join('&');
89 |
90 | /**
91 | * Merge objects deep.
92 | *
93 | * @param {object} target
94 | * @param {object} source
95 | *
96 | * @return {object}
97 | */
98 | export const mergeObjects = (target: Record, source: Record) => {
99 | if (!isObject(target) && !isObject(source)) {
100 | return target;
101 | }
102 |
103 | for (const key in source) {
104 | if (source[key] === null && (target[key] === undefined || target[key] === null)) {
105 | target[key] = null;
106 | } else if (source[key] instanceof Array) {
107 | if (!target[key]) {
108 | target[key] = [];
109 | }
110 |
111 | target[key] = target[key].concat(source[key]);
112 | } else if (isObject(source[key])) {
113 | if (!isObject(target[key])) {
114 | target[key] = {};
115 | }
116 |
117 | mergeObjects(target[key], source[key]);
118 | } else {
119 | if (target === undefined) {
120 | target = {};
121 | }
122 |
123 | target[key] = source[key];
124 | }
125 | }
126 |
127 | return target;
128 | };
129 |
--------------------------------------------------------------------------------
/packages/client/test/Client.spec.ts:
--------------------------------------------------------------------------------
1 | import Client from '../src';
2 | import MockTransport from './mocks/MockTransport';
3 | import expect from 'expect';
4 |
5 | const transport = new MockTransport();
6 | const endpoint = 'http://wordpress.test/wp-json';
7 | const client = new Client({ transport, endpoint });
8 | const defaultOptions = {
9 | endpoint: '',
10 | namespace: 'wp/v2',
11 | nonce: '',
12 | config: {
13 | headers: {
14 | 'Content-Type': 'application/json'
15 | }
16 | },
17 | resource: '',
18 | restore: true
19 | };
20 |
21 | describe('Client', () => {
22 | beforeEach(() => {
23 | transport.resetMocks();
24 | });
25 |
26 | it('sets transport property', () => {
27 | expect(client.transport).toBe(transport);
28 | });
29 |
30 | it('throws error when missing transport', () => {
31 | try {
32 | new Client({ transport: undefined });
33 | } catch (error: any) {
34 | expect(error instanceof TypeError).toBe(true);
35 | expect(error.message).toBe('Transport is required option, none was set.');
36 | }
37 | });
38 |
39 | it('has default options', () => {
40 | const ylletClient = new Client({ transport });
41 | expect(ylletClient.options).toEqual(defaultOptions);
42 | });
43 |
44 | it('handle bad options input', () => {
45 | const ylletClient = new Client(undefined);
46 | expect(ylletClient.options).toEqual(defaultOptions);
47 | });
48 |
49 | it('has nonce header', () => {
50 | const ylletClient = new Client({
51 | nonce: 'XYZ'
52 | });
53 | expect(ylletClient.options.config.headers['X-WP-Nonce']).toEqual('XYZ');
54 | });
55 |
56 | it('just endpoint option', () => {
57 | const ylletClient = new Client(endpoint);
58 | expect(ylletClient.options).toEqual({
59 | ...defaultOptions,
60 | endpoint: endpoint
61 | });
62 | });
63 |
64 | it('bad options input', () => {
65 | const ylletClient = new Client(undefined);
66 | expect(ylletClient.options).toEqual(defaultOptions);
67 | });
68 |
69 | it('merges options', () => {
70 | const ylletClient = new Client({
71 | transport,
72 | headers: {
73 | 'X-Test': 'Test'
74 | },
75 | endpoint: 'https://wordpress.test/wp-json',
76 | config: {
77 | foo: 'bar'
78 | }
79 | });
80 | expect(ylletClient.options).toEqual({
81 | endpoint: 'https://wordpress.test/wp-json',
82 | namespace: 'wp/v2',
83 | nonce: '',
84 | config: {
85 | foo: 'bar',
86 | headers: {
87 | 'Content-Type': 'application/json',
88 | 'X-Test': 'Test'
89 | }
90 | },
91 | resource: '',
92 | restore: true
93 | });
94 | });
95 |
96 | it('has HTTP methods', () => {
97 | expect(typeof client.get).toBe('function');
98 | expect(typeof client.create).toBe('function');
99 | expect(typeof client.update).toBe('function');
100 | expect(typeof client.delete).toBe('function');
101 | });
102 |
103 | it('has API Resource methods', () => {
104 | [
105 | 'categories',
106 | 'comments',
107 | 'media',
108 | 'statuses',
109 | 'pages',
110 | 'posts',
111 | 'settings',
112 | 'tags',
113 | 'taxonomies',
114 | 'types',
115 | 'users',
116 | 'search'
117 | ].forEach((method) => {
118 | client[method]();
119 | expect(client.options.resource).toBe(method);
120 | });
121 | });
122 | });
123 |
--------------------------------------------------------------------------------
/packages/client/test/Transport/index.spec.ts:
--------------------------------------------------------------------------------
1 | import FormData from 'isomorphic-form-data';
2 | import fetchMock from 'fetch-mock';
3 | import Transport from '../../src/Transport';
4 | // @ts-ignore
5 | import { HTTPError } from '@yllet/support';
6 |
7 | const transport = new Transport();
8 | const endpoint = 'https://wp.com/wp-json';
9 | const verbs = ['GET', 'POST', 'PUT', 'DELETE'];
10 |
11 | beforeEach(() => {
12 | fetchMock.reset();
13 | });
14 |
15 | describe('request calls', () => {
16 | verbs.forEach((verb) => {
17 | it(`${verb} calls fetch once`, () => {
18 | fetchMock.once(endpoint, {});
19 | transport[verb.toLocaleLowerCase()](endpoint).catch(console.log);
20 | expect((fetchMock.calls() as any).length).toEqual(1);
21 | });
22 | });
23 | });
24 |
25 | describe('verbs', () => {
26 | verbs.forEach((verb) => {
27 | it(`${verb} sends correct http verb`, () => {
28 | fetchMock.once(
29 | endpoint,
30 | {},
31 | {
32 | method: verb,
33 | },
34 | );
35 | transport[verb.toLocaleLowerCase()](endpoint);
36 | expect((fetchMock.calls() as any)[0][1].method).toEqual(verb);
37 | });
38 | });
39 | });
40 |
41 | describe('url', () => {
42 | verbs.forEach((verb) => {
43 | it(`${verb} calls correct url`, () => {
44 | fetchMock.once(endpoint, {});
45 | transport[verb.toLocaleLowerCase()](endpoint);
46 | expect((fetchMock.calls() as any)[0][0]).toEqual(endpoint);
47 | });
48 | });
49 | });
50 |
51 | describe('headers', () => {
52 | const config = {
53 | headers: {
54 | 'X-Foo': 'bar',
55 | },
56 | };
57 |
58 | verbs.forEach((verb) => {
59 | it(`${verb} sends correct headers`, () => {
60 | fetchMock.once(endpoint, {});
61 | transport[verb.toLocaleLowerCase()](endpoint, {}, config);
62 | expect((fetchMock.calls() as any)[0][1].headers).toEqual(config.headers);
63 | });
64 | });
65 | });
66 |
67 | describe('merge config', () => {
68 | const config = {
69 | foo: 'bar',
70 | bar: 'foo',
71 | };
72 |
73 | verbs.forEach((verb) => {
74 | let expected = {
75 | ...config,
76 | method: verb,
77 | };
78 |
79 | if (['POST', 'PUT'].includes(verb)) {
80 | expected = {
81 | ...expected,
82 | body: '{}',
83 | } as any;
84 | }
85 |
86 | it(`${verb} passes custom config`, () => {
87 | fetchMock.once(endpoint, {});
88 | transport[verb.toLocaleLowerCase()](endpoint, {}, config);
89 | expect((fetchMock.calls() as any)[0][1]).toEqual(expected);
90 | });
91 | });
92 | });
93 |
94 | describe('with data', () => {
95 | const data = { foo: 'bar', posts: [21, 33, 150] };
96 |
97 | verbs.forEach((verb) => {
98 | it(`${verb} sends data`, () => {
99 | if (['GET', 'DELETE'].includes(verb)) {
100 | fetchMock.once('*', {});
101 | transport[verb.toLocaleLowerCase()](endpoint, data);
102 | expect((fetchMock.calls() as any)[0][0]).toBe(
103 | endpoint + '?foo=bar&posts[]=21&posts[]=33&posts[]=150',
104 | );
105 | expect((fetchMock.calls() as any)[0][1].body).toBe(undefined);
106 | } else {
107 | fetchMock.once('*', {});
108 | transport[verb.toLocaleLowerCase()](endpoint, data);
109 | expect((fetchMock.calls() as any)[0][1].body).toEqual(JSON.stringify(data));
110 | }
111 | });
112 | });
113 | });
114 |
115 | describe('with form data', () => {
116 | const formData = new FormData();
117 | formData.append('foo', 'bar');
118 |
119 | verbs.forEach((verb) => {
120 | it(`${verb} sends form data`, () => {
121 | if (['GET', 'DELETE'].includes(verb)) {
122 | try {
123 | fetchMock.once(endpoint, {});
124 | transport[verb.toLocaleLowerCase()](endpoint, formData);
125 | } catch (error: any) {
126 | expect(error instanceof TypeError).toBe(true);
127 | expect(error.message).toBe('Unable to encode FormData for GET, DELETE requests');
128 | }
129 | } else {
130 | fetchMock.once(endpoint, {});
131 | transport[verb.toLocaleLowerCase()](endpoint, formData);
132 | expect((fetchMock.calls() as any)[0][1].body instanceof FormData).toBe(true);
133 | }
134 | });
135 | });
136 | });
137 |
138 | describe('without data', () => {
139 | verbs.forEach((verb) => {
140 | it(`${verb} sends data`, () => {
141 | fetchMock.once(endpoint, {});
142 | transport[verb.toLocaleLowerCase()](endpoint);
143 | if (['GET', 'DELETE'].includes(verb)) {
144 | expect((fetchMock.calls() as any)[0][0]).toBe(endpoint);
145 | expect((fetchMock.calls() as any)[0][1].body).toBe(undefined);
146 | } else {
147 | expect((fetchMock.calls() as any)[0][1].body).toBe(undefined);
148 | }
149 | });
150 | });
151 | });
152 |
153 | describe('returns json', () => {
154 | verbs.forEach((verb) => {
155 | it(`${verb} returns data`, () => {
156 | fetchMock.once(endpoint, { data: { mock: 'response' } });
157 | transport[verb.toLocaleLowerCase()](endpoint).then((response: any) => {
158 | expect(response.data).toEqual({ mock: 'response' });
159 | });
160 | });
161 | });
162 | });
163 |
164 | describe('http exceptions', () => {
165 | const response = {
166 | status: 503,
167 | body: { foo: 'bar' },
168 | };
169 |
170 | verbs.forEach((verb) => {
171 | it(`${verb} throws http exceptions`, () => {
172 | fetchMock.once('*', response);
173 | return transport[verb.toLocaleLowerCase()](endpoint).catch((error: any) => {
174 | expect(error.toString()).toContain('HTTPError');
175 | expect(error.response).toEqual({ foo: 'bar' });
176 | });
177 | });
178 | });
179 | });
180 |
--------------------------------------------------------------------------------
/packages/client/test/middlewares.spec.ts:
--------------------------------------------------------------------------------
1 | import Client from '../src';
2 | import type { Next } from '../src';
3 | import MockTransport from './mocks/MockTransport';
4 | import expect from 'expect';
5 |
6 | const responses = {
7 | get: {
8 | posts: {}
9 | }
10 | };
11 | const transport = new MockTransport(responses);
12 | const endpoint = 'http://wordpress.test/wp-json';
13 | const client = new Client({ transport, endpoint });
14 |
15 | const middlewareOne = (client: Client, next: Next) => {
16 | client.header('X-Foo', 'Bar');
17 | return next();
18 | };
19 |
20 | const middlewareTwo = async (client: Client, next: Next) => {
21 | if (typeof jest !== 'undefined') {
22 | jest.useFakeTimers();
23 | setTimeout(() => {
24 | client.header('X-Foo', 'Bar');
25 | return next();
26 | }, 1000);
27 | jest.runAllTimers();
28 | } else {
29 | await new Promise((r) => setTimeout(r, 1000));
30 | client.header('X-Foo', 'Bar');
31 | return next();
32 | }
33 | };
34 |
35 | const middlewareThree = (client: Client, next: Next) => {
36 | client
37 | .endpoint('https://woocommerce.com/wp-json')
38 | .namespace('wc/v3')
39 | .resource('products');
40 | next();
41 | };
42 |
43 | const middlewareFour = (client: Client, next: Next) => {
44 | client.transport = new MockTransport() as any;
45 | next();
46 | };
47 |
48 | describe('Middlewares', () => {
49 | beforeEach(() => {
50 | transport.resetMocks();
51 | });
52 |
53 | it('default middleware property', () => {
54 | expect(client.middlewares).toEqual([]);
55 | });
56 |
57 | it('add middlewares as option', () => {
58 | const ylletClient = new Client({ middlewares: [middlewareOne] });
59 | expect(ylletClient.middlewares).toEqual([middlewareOne]);
60 | });
61 |
62 | it('add middlewares with use', () => {
63 | const ylletClient = new Client();
64 | expect(ylletClient.middlewares).toEqual([]);
65 |
66 | ylletClient.use(middlewareOne);
67 | expect(ylletClient.middlewares).toEqual([middlewareOne]);
68 |
69 | ylletClient.use([middlewareOne]);
70 | expect(ylletClient.middlewares).toEqual([middlewareOne, middlewareOne]);
71 | });
72 |
73 | it('run middleware one', async () => {
74 | const ylletClient = new Client({
75 | headers: { 'X-Requested-With': 'Yllet' },
76 | middlewares: [middlewareOne],
77 | transport
78 | });
79 | expect((transport as any).get.mock.calls).toEqual([]);
80 |
81 | ylletClient
82 | .posts()
83 | .get()
84 | .then((res) => {
85 | expect(res).toBe(responses.get);
86 | expect((transport as any).get.mock.calls[0][0]).toBe('/wp/v2/posts');
87 | expect(
88 | (transport as any).get.mock.calls[0][2].headers['X-Requested-With']
89 | ).toBe('Yllet');
90 | expect((transport as any).get.mock.calls[0][2].headers['X-Foo']).toBe(
91 | 'Bar'
92 | );
93 | });
94 |
95 | ylletClient
96 | .posts()
97 | .get()
98 | .then((res) => {
99 | expect(res).toBe(responses.get);
100 | expect((transport as any).get.mock.calls[1][0]).toBe('/wp/v2/posts');
101 | expect(
102 | (transport as any).get.mock.calls[1][2].headers['X-Requested-With']
103 | ).toBe('Yllet');
104 | expect((transport as any).get.mock.calls[1][2].headers['X-Foo']).toBe(
105 | 'Bar'
106 | );
107 | });
108 | });
109 |
110 | it('run middleware two', async () => {
111 | const ylletClient = new Client({
112 | headers: { 'X-Requested-With': 'Yllet' },
113 | middlewares: [middlewareTwo],
114 | transport
115 | });
116 | expect((transport as any).get.mock.calls).toEqual([]);
117 |
118 | if (typeof jest !== 'undefined') {
119 | const res = await ylletClient.posts().get();
120 | expect(res).toBe(responses.get);
121 | expect((transport as any).get.mock.calls[0][0]).toBe('/wp/v2/posts');
122 | expect(
123 | (transport as any).get.mock.calls[0][2].headers['X-Requested-With']
124 | ).toBe('Yllet');
125 | expect((transport as any).get.mock.calls[0][2].headers['X-Foo']).toBe(
126 | 'Bar'
127 | );
128 | }
129 |
130 | ylletClient
131 | .posts()
132 | .get()
133 | .then((res) => {
134 | expect(res).toBe(responses.get);
135 | expect((transport as any).get.mock.calls[1][0]).toBe('/wp/v2/posts');
136 | expect(
137 | (transport as any).get.mock.calls[1][2].headers['X-Requested-With']
138 | ).toBe('Yllet');
139 | expect((transport as any).get.mock.calls[1][2].headers['X-Foo']).toBe(
140 | 'Bar'
141 | );
142 | });
143 | });
144 |
145 | it('run middleware three', async () => {
146 | const ylletClient = new Client({
147 | headers: { 'X-Requested-With': 'Yllet' },
148 | middlewares: [middlewareThree],
149 | restore: false,
150 | transport
151 | });
152 | expect((transport as any).get.mock.calls).toEqual([]);
153 |
154 | ylletClient
155 | .posts()
156 | .get()
157 | .then((res) => {
158 | expect(res).toBe(responses.get);
159 | expect((transport as any).get.mock.calls[0][0]).toBe('/wp/v2/posts');
160 | expect(ylletClient.options.endpoint).toBe('');
161 | expect(ylletClient.options.namespace).toBe('wp/v2');
162 | expect(ylletClient.options.resource).toBe('posts');
163 | });
164 | });
165 |
166 | it('run middleware four', async () => {
167 | const ylletClient = new Client({
168 | headers: { 'X-Requested-With': 'Yllet' },
169 | middlewares: [middlewareFour],
170 | restore: false,
171 | transport
172 | });
173 |
174 | expect((transport as any).get.mock.calls).toEqual([]);
175 | expect(ylletClient.transport).toBeInstanceOf(MockTransport);
176 |
177 | ylletClient
178 | .posts()
179 | .get()
180 | .then((res) => {
181 | expect(res).toBe(responses.get);
182 | console.log(ylletClient.transport);
183 | expect(ylletClient.transport).toBeInstanceOf(MockTransport);
184 | });
185 | });
186 | });
187 |
--------------------------------------------------------------------------------
/examples/parcel/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "parcel-example",
3 | "lockfileVersion": 2,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "name": "parcel-example",
8 | "dependencies": {
9 | "@yllet/client": "^3.0.1"
10 | }
11 | },
12 | "node_modules/@yllet/client": {
13 | "version": "3.0.1",
14 | "resolved": "https://registry.npmjs.org/@yllet/client/-/client-3.0.1.tgz",
15 | "integrity": "sha512-ktS3gUIh/CPbbkhvrIxQ40Ws2YdBNiOZKcLOJKdsZnnfEWNus9CUUMUV/8Ev4a1TI1N6WVnvwgMNciiuwdWR1Q==",
16 | "dependencies": {
17 | "@yllet/support": "^3.0.1",
18 | "isomorphic-form-data": "^2.0.0"
19 | }
20 | },
21 | "node_modules/@yllet/support": {
22 | "version": "3.0.1",
23 | "resolved": "https://registry.npmjs.org/@yllet/support/-/support-3.0.1.tgz",
24 | "integrity": "sha512-NGbwwlgt8CK0RiR+rzj9ak3ikUaL4M7k9ebnEHbjlLPRfiufBy/1tUA3obaUYms3p/SI8J0it0HEUn7UXQmMzg=="
25 | },
26 | "node_modules/asynckit": {
27 | "version": "0.4.0",
28 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
29 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
30 | },
31 | "node_modules/combined-stream": {
32 | "version": "1.0.8",
33 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
34 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
35 | "dependencies": {
36 | "delayed-stream": "~1.0.0"
37 | },
38 | "engines": {
39 | "node": ">= 0.8"
40 | }
41 | },
42 | "node_modules/delayed-stream": {
43 | "version": "1.0.0",
44 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
45 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
46 | "engines": {
47 | "node": ">=0.4.0"
48 | }
49 | },
50 | "node_modules/form-data": {
51 | "version": "2.5.1",
52 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
53 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
54 | "dependencies": {
55 | "asynckit": "^0.4.0",
56 | "combined-stream": "^1.0.6",
57 | "mime-types": "^2.1.12"
58 | },
59 | "engines": {
60 | "node": ">= 0.12"
61 | }
62 | },
63 | "node_modules/isomorphic-form-data": {
64 | "version": "2.0.0",
65 | "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-2.0.0.tgz",
66 | "integrity": "sha512-TYgVnXWeESVmQSg4GLVbalmQ+B4NPi/H4eWxqALKj63KsUrcu301YDjBqaOw3h+cbak7Na4Xyps3BiptHtxTfg==",
67 | "dependencies": {
68 | "form-data": "^2.3.2"
69 | }
70 | },
71 | "node_modules/mime-db": {
72 | "version": "1.42.0",
73 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
74 | "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==",
75 | "engines": {
76 | "node": ">= 0.6"
77 | }
78 | },
79 | "node_modules/mime-types": {
80 | "version": "2.1.25",
81 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
82 | "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
83 | "dependencies": {
84 | "mime-db": "1.42.0"
85 | },
86 | "engines": {
87 | "node": ">= 0.6"
88 | }
89 | }
90 | },
91 | "dependencies": {
92 | "@yllet/client": {
93 | "version": "3.0.1",
94 | "resolved": "https://registry.npmjs.org/@yllet/client/-/client-3.0.1.tgz",
95 | "integrity": "sha512-ktS3gUIh/CPbbkhvrIxQ40Ws2YdBNiOZKcLOJKdsZnnfEWNus9CUUMUV/8Ev4a1TI1N6WVnvwgMNciiuwdWR1Q==",
96 | "requires": {
97 | "@yllet/support": "^3.0.1",
98 | "isomorphic-form-data": "^2.0.0"
99 | }
100 | },
101 | "@yllet/support": {
102 | "version": "3.0.1",
103 | "resolved": "https://registry.npmjs.org/@yllet/support/-/support-3.0.1.tgz",
104 | "integrity": "sha512-NGbwwlgt8CK0RiR+rzj9ak3ikUaL4M7k9ebnEHbjlLPRfiufBy/1tUA3obaUYms3p/SI8J0it0HEUn7UXQmMzg=="
105 | },
106 | "asynckit": {
107 | "version": "0.4.0",
108 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
109 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
110 | },
111 | "combined-stream": {
112 | "version": "1.0.8",
113 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
114 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
115 | "requires": {
116 | "delayed-stream": "~1.0.0"
117 | }
118 | },
119 | "delayed-stream": {
120 | "version": "1.0.0",
121 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
122 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
123 | },
124 | "form-data": {
125 | "version": "2.5.1",
126 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
127 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
128 | "requires": {
129 | "asynckit": "^0.4.0",
130 | "combined-stream": "^1.0.6",
131 | "mime-types": "^2.1.12"
132 | }
133 | },
134 | "isomorphic-form-data": {
135 | "version": "2.0.0",
136 | "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-2.0.0.tgz",
137 | "integrity": "sha512-TYgVnXWeESVmQSg4GLVbalmQ+B4NPi/H4eWxqALKj63KsUrcu301YDjBqaOw3h+cbak7Na4Xyps3BiptHtxTfg==",
138 | "requires": {
139 | "form-data": "^2.3.2"
140 | }
141 | },
142 | "mime-db": {
143 | "version": "1.42.0",
144 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
145 | "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ=="
146 | },
147 | "mime-types": {
148 | "version": "2.1.25",
149 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
150 | "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
151 | "requires": {
152 | "mime-db": "1.42.0"
153 | }
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/docs/v1/readme.md:
--------------------------------------------------------------------------------
1 | # Yllet docs v1
2 |
3 | Yllet is a set of packages for the WordPress API for both React and non-React projects. The client is built on top of [axios](https://github.com/axios/axios).
4 |
5 | ## Installation
6 |
7 | To install the WordPress API client:
8 |
9 | ```
10 | npm install --save yllet
11 | ```
12 |
13 | To install the package with React bindings:
14 |
15 | ```
16 | npm install --save yllet-react
17 | ```
18 |
19 | ## Usage
20 |
21 | Fetch all posts:
22 |
23 | ```js
24 | import Client from 'yllet';
25 |
26 | const client = new Client({
27 | endpoint: 'https://demo.wp-api.org/wp-json/'
28 | });
29 |
30 | client
31 | .posts()
32 | .get()
33 | .then((res) => {
34 | console.log(res.data);
35 | })
36 | .catch((err) => {
37 | console.log('Error: ' + err.message);
38 | });
39 | ```
40 |
41 | ## Client options
42 |
43 | ```js
44 | {
45 | // Basic auth.
46 | auth: {
47 | username: '',
48 | password: ''
49 | },
50 |
51 | // Axios settings.
52 | axios: {},
53 |
54 | // HTTP headers.
55 | headers: {},
56 |
57 | // WordPress API endpoint.
58 | endpoint: '',
59 |
60 | // Default namespace.
61 | namespace: 'wp/v2'
62 | }
63 | ```
64 |
65 | If you need to pass something special to Axios you can use `axios` object. Both `auth` and `headers` will be merged to `axios` object.
66 |
67 | You can also set headers using `client.header()` with key/value or object.
68 |
69 | The Axios instance is accessable on the client instance, just use `client.axios` and then you can use interceptors or something other.
70 |
71 | ## Resources
72 |
73 | Yllet client instance provides the following basic request methods:
74 |
75 | - `client.categories()`
76 | - `client.comments()`
77 | - `client.media()`
78 | - `client.statuses()`
79 | - `client.posts()`
80 | - `client.pages()`
81 | - `client.settings()`
82 | - `client.tags()`
83 | - `client.taxonomies()`
84 | - `client.types()`
85 | - `client.users()`
86 |
87 | Using any request methods sets the path so you don't have to write `client.get('posts/1')` each time instead you can just write `client.posts().get(1)`
88 |
89 | Adding custom request methods is easy (example [WooCommerce REST API](https://woocommerce.github.io/woocommerce-rest-api-docs/)):
90 |
91 | ```js
92 | // Example: http://wordpress.test/wp-json/wc/v2/products
93 | client.products = () => client.namespace('wc/v2').resource('products');
94 | ```
95 |
96 | Then you can just call `client.products()` like you do with `client.posts()`
97 |
98 | ```js
99 | client
100 | .products()
101 | .get()
102 | .then((res) => {
103 | console.log(res.data);
104 | })
105 | .catch((err) => {
106 | console.log('Error: ' + err.message);
107 | });
108 | ```
109 |
110 | ## Params
111 |
112 | You can pass a object with the same name as as the existing params. You can write `per_page` or `perPage` when the param contains a underscore.
113 |
114 | ```js
115 | client
116 | .posts()
117 | .get({
118 | slug: 'hello-world',
119 | perPage: 1 // or per_page
120 | })
121 | .then((res) => {
122 | console.log(res.data);
123 | })
124 | .catch((err) => {
125 | console.log('Error: ' + err.message);
126 | });
127 | ```
128 |
129 | You can also set global params using key/value or object:
130 |
131 | ```js
132 | client.param('source', 'yllet');
133 | ```
134 |
135 | All global params can be accessed with `client.params`
136 |
137 | ## Embed data
138 |
139 | WordPress API support embedding of resources and instead of having to provide `_embed=true` as a param on every request we can simpley use `embed()` before any request method.
140 |
141 | More about WordPress API embedding can you read [here](https://developer.wordpress.org/rest-api/using-the-rest-api/linking-and-embedding/#embedding).
142 |
143 | ```js
144 | client
145 | .posts()
146 | .embed()
147 | .get({
148 | slug: 'hello-world'
149 | })
150 | .then((res) => {
151 | console.log(res.data);
152 | })
153 | .catch((err) => {
154 | console.log('Error: ' + err.message);
155 | });
156 | ```
157 |
158 | ## File uploading
159 |
160 | When Uploading a file you should use `client.file(file, [name])` to specify a file or a file buffer to attach to the request with a name (optional).
161 |
162 | Browser example:
163 |
164 | ```js
165 | const file = document.getElementById('my-file').files[0];
166 |
167 | client
168 | .media()
169 | .file(file)
170 | .create({
171 | title: 'Test image'
172 | })
173 | .then((res) => {
174 | console.log(res.data);
175 | })
176 | .catch((err) => {
177 | console.log('Error: ', err);
178 | });
179 | ```
180 |
181 | Node example:
182 |
183 | ```js
184 | client
185 | .media()
186 | .file(fs.createReadStream('me.jpg'))
187 | .create({
188 | title: 'Test image'
189 | })
190 | .then((res) => {
191 | console.log(res.data);
192 | })
193 | .catch((err) => {
194 | console.log('Error: ', err);
195 | });
196 | ```
197 |
198 | ## Discover the REST API from a URL
199 |
200 | ```js
201 | import Client from 'yllet';
202 |
203 | Client.discover('http://demo.wp-api.org/')
204 | .then((url) => {
205 | console.log(url);
206 | })
207 | .catch((err) => {
208 | console.log('Error: ', err);
209 | });
210 | ```
211 |
212 | ## React bindings
213 |
214 | Yllets React package contains a provider component that you can use like this:
215 |
216 | ```js
217 | import React from 'react';
218 | import ReactDOM from 'react-dom';
219 | import App from './App';
220 |
221 | import Client from 'yllet';
222 | import { Provider } from 'yllet-react';
223 |
224 | const client = new Client({
225 | endpoint: 'https://demo.wp-api.org/wp-json/'
226 | });
227 |
228 | ReactDOM.render(
229 |
230 |
231 | ,
232 | document.getElementById('root')
233 | );
234 | ```
235 |
236 | In your application component you can use the `withClient` component enhancer to pass along the `client` to your component.
237 |
238 | ```js
239 | import React from 'react';
240 | import { withClient } from 'yllet-react';
241 |
242 | class App extends React.Component {}
243 |
244 | export default withClient(App);
245 | ```
246 |
247 | Then you can use `this.props.client` the same way as if it was a standalone client.
248 |
249 | You can also use `withClientData` to pass the response data or the error from WordPress REST API.
250 |
251 | ```js
252 | import React from 'react';
253 | import { withClientData } from 'yllet-react';
254 |
255 | class Post extends React.Component {}
256 |
257 | export default withClientData((client, props) => {
258 | return client.posts().get(1);
259 | })(Post);
260 | ```
261 |
262 | Then you can use `this.props.data` or `this.props.error` and `this.props.loading`
263 |
--------------------------------------------------------------------------------
/packages/support/test/index.spec.ts:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | isObject,
4 | mergeObjects,
5 | objectKeysToSnakeCase,
6 | qsEncode
7 | } from '../src';
8 |
9 | describe('isObject', () => {
10 | it('can test for objects', () => {
11 | [
12 | [true, {}],
13 | [false, 1],
14 | [false, false],
15 | [false, []],
16 | [false, ''],
17 | [false, 1.2],
18 | [false, new Error()]
19 | ].forEach((d) => {
20 | expect(d[0]).toBe(isObject(d[1]));
21 | });
22 | });
23 | });
24 |
25 | describe('objectKeysToSnakeCase', () => {
26 | it('can snake case object keys', () => {
27 | [
28 | [
29 | {
30 | test_data: 1
31 | },
32 | {
33 | testData: 1
34 | }
35 | ],
36 | [
37 | {
38 | test: {
39 | test_data: 1
40 | }
41 | },
42 | {
43 | test: {
44 | testData: 1
45 | }
46 | }
47 | ],
48 | [
49 | {
50 | abc: [
51 | {
52 | abc: {
53 | abc_data: 1
54 | }
55 | }
56 | ]
57 | },
58 | {
59 | abc: [
60 | {
61 | abc: {
62 | abcData: 1
63 | }
64 | }
65 | ]
66 | }
67 | ]
68 | ].forEach((d) => {
69 | const obj = objectKeysToSnakeCase(d[1]);
70 | expect(d[0]).toEqual(obj);
71 | });
72 | });
73 | });
74 |
75 | describe('qsEncode', () => {
76 | it('convert object to query string', () => {
77 | [
78 | [
79 | {
80 | a: 100,
81 | b: 'with spaces',
82 | c: [1, 2, 3],
83 | d: { x: 9, y: 8 }
84 | },
85 | 'a=100&b=with%20spaces&c[]=1&c[]=2&c[]=3&d[x]=9&d[y]=8'
86 | ],
87 | [
88 | {
89 | foo: 'bar',
90 | posts: [21, 33, 150]
91 | },
92 | 'foo=bar&posts[]=21&posts[]=33&posts[]=150'
93 | ],
94 | [
95 | {
96 | foo: [1, [2], 3],
97 | bar: ['one', ['two'], 'three']
98 | },
99 | 'foo[]=1&foo[]=2&foo[]=3&bar[]=one&bar[]=two&bar[]=three'
100 | ],
101 | [
102 | {
103 | hello: 'world',
104 | foo: 'bar',
105 | colors: ['red', 'green', 'blue', 'yellow'],
106 | numbers: [100, 200, [300]],
107 | on: true,
108 | off: false,
109 | purple: 'haze'
110 | },
111 | 'hello=world&foo=bar&colors[]=red&colors[]=green&colors[]=blue&colors[]=yellow&numbers[]=100&numbers[]=200&numbers[]=300&on=true&off=false&purple=haze'
112 | ]
113 | ].forEach((d) => {
114 | // @ts-ignore
115 | const str = qsEncode(d[0]);
116 | // @ts-ignore
117 | expect(str).toEqual(d[1]);
118 | });
119 | });
120 | });
121 |
122 | describe('mergeObjects', () => {
123 | it('can merge objects', () => {
124 | [
125 | [undefined, undefined, undefined],
126 | [
127 | {
128 | foo: null
129 | },
130 | {
131 | foo: null
132 | },
133 | {
134 | foo: null
135 | }
136 | ],
137 | [
138 | {
139 | foo: { bar: 3 },
140 | array: [
141 | {
142 | does: 'work',
143 | too: [1, 2, 3]
144 | }
145 | ]
146 | },
147 | {
148 | foo: { baz: 4 },
149 | quux: 5,
150 | array: [
151 | {
152 | does: 'work',
153 | too: [4, 5, 6]
154 | },
155 | {
156 | really: 'yes'
157 | }
158 | ],
159 | array2: ['bar']
160 | },
161 | {
162 | foo: {
163 | bar: 3,
164 | baz: 4
165 | },
166 | array: [
167 | {
168 | does: 'work',
169 | too: [1, 2, 3]
170 | },
171 | {
172 | does: 'work',
173 | too: [4, 5, 6]
174 | },
175 | {
176 | really: 'yes'
177 | }
178 | ],
179 | array2: ['bar'],
180 | quux: 5
181 | }
182 | ],
183 | [
184 | {
185 | key1: 'value1',
186 | key3: 'value3'
187 | },
188 | {
189 | key1: 'changed',
190 | key2: 'value2'
191 | },
192 | {
193 | key1: 'changed',
194 | key2: 'value2',
195 | key3: 'value3'
196 | }
197 | ],
198 | [
199 | {
200 | key1: {
201 | subkey1: 'value1',
202 | subkey2: 'value2'
203 | }
204 | },
205 | {
206 | key1: {
207 | subkey1: 'changed',
208 | subkey3: 'added'
209 | }
210 | },
211 | {
212 | key1: {
213 | subkey1: 'changed',
214 | subkey2: 'value2',
215 | subkey3: 'added'
216 | }
217 | }
218 | ],
219 | [
220 | {
221 | key1: 'value1',
222 | key2: 'value2'
223 | },
224 | {
225 | key1: {
226 | subkey1: 'subvalue1',
227 | subkey2: 'subvalue2'
228 | }
229 | },
230 | {
231 | key1: {
232 | subkey1: 'subvalue1',
233 | subkey2: 'subvalue2'
234 | },
235 | key2: 'value2'
236 | }
237 | ],
238 | [
239 | {
240 | b: {
241 | c: {}
242 | }
243 | },
244 | {
245 | a: {}
246 | },
247 | {
248 | a: {},
249 | b: {
250 | c: {}
251 | }
252 | }
253 | ],
254 | [
255 | {
256 | a: {
257 | d: 'bar'
258 | }
259 | },
260 | {
261 | b: {
262 | c: 'foo'
263 | }
264 | },
265 | {
266 | a: {
267 | d: 'bar'
268 | },
269 | b: {
270 | c: 'foo'
271 | }
272 | }
273 | ],
274 | [
275 | {
276 | key1: {
277 | subkey1: 'subvalue1',
278 | subkey2: 'subvalue2'
279 | },
280 | key2: 'value2'
281 | },
282 | {
283 | key1: 'value1'
284 | },
285 | {
286 | key1: 'value1',
287 | key2: 'value2'
288 | }
289 | ],
290 | [
291 | {
292 | config: {}
293 | },
294 | {
295 | config: {
296 | headers: {
297 | key1: 'value1'
298 | }
299 | }
300 | },
301 | {
302 | config: {
303 | headers: {
304 | key1: 'value1'
305 | }
306 | }
307 | }
308 | ]
309 | ].forEach((d) => {
310 | // @ts-ignore
311 | const obj = mergeObjects(d[0], d[1]);
312 | // @ts-ignore
313 | expect(obj).toEqual(d[2]);
314 | });
315 | });
316 | });
317 |
--------------------------------------------------------------------------------
/docs/v2/readme.md:
--------------------------------------------------------------------------------
1 | # Yllet docs v2
2 |
3 | Yllet is a set of packages for the WordPress API for both React and non-React projects. The client is built on top of fetch, you can add your own transport by creating it, you can read more [here](#transport-layers).
4 |
5 | Yllet comes with [tree-shakable](https://webpack.js.org/guides/tree-shaking/) ESM or CJS builds, that fits into the modern ES6 JavaScript ecosystem. All code are tiny and well tested with both unit and browser tests.
6 |
7 | ## Installation
8 |
9 | To install the WordPress API client
10 |
11 | ```
12 | npm install --save @yllet/client
13 | ```
14 |
15 | To install the package with React bindings
16 |
17 | ```
18 | npm install --save @yllet/react
19 | ```
20 |
21 | ## Usage
22 |
23 | Fetch all posts
24 |
25 | ```js
26 | import Client from '@yllet/client';
27 |
28 | const client = new Client({
29 | endpoint: 'https://demo.wp-api.org/wp-json/'
30 | });
31 |
32 | client
33 | .posts()
34 | .get()
35 | .then((res) => {
36 | console.log(res.data);
37 | })
38 | .catch((err) => {
39 | console.log('Error: ' + err.message);
40 | });
41 | ```
42 |
43 | ## Client options
44 |
45 | ```js
46 | {
47 | // HTTP Headers
48 | headers: {
49 | 'Content-Type': 'application/json'
50 | },
51 |
52 | // WordPress API endpoint.
53 | endpoint: '',
54 |
55 | // Default namespace.
56 | namespace: 'wp/v2'
57 |
58 | // WP Nonce, adds X-WP-Nonce header.
59 | nonce: '',
60 |
61 | // Restore default options when using endpoint, namespace and resource methods.
62 | restore: true,
63 | }
64 | ```
65 |
66 | ## Resources
67 |
68 | Yllet client instance provides the following basic request methods
69 |
70 | - `client.categories()`
71 | - `client.comments()`
72 | - `client.media()`
73 | - `client.statuses()`
74 | - `client.posts()`
75 | - `client.pages()`
76 | - `client.search()`
77 | - `client.settings()`
78 | - `client.tags()`
79 | - `client.taxonomies()`
80 | - `client.types()`
81 | - `client.users()`
82 |
83 | Using any request methods sets the path so you don't have to write `client.get('posts/1')` each time instead you can just write `client.posts().get(1)`
84 |
85 | Adding custom request methods is easy (example [WooCommerce REST API](https://woocommerce.github.io/woocommerce-rest-api-docs/))
86 |
87 | ```js
88 | // To call another endpoint, namespace and resource.
89 | client
90 | .endpoint('https://wp.com/wp-json')
91 | .namespace('wc/v2')
92 | .resource('products')
93 | .get()
94 | .then((res) => {
95 | console.log(res.data);
96 | })
97 | .catch((err) => {
98 | console.log('Error: ' + err.message);
99 | });
100 |
101 | // To store the client with new namespace, resource and endpoint.
102 | client.products = () =>
103 | client
104 | .endpoint('https://wp.com/wp-json')
105 | .namespace('wc/v2')
106 | .resource('products');
107 |
108 | // Then you can just call `client.products()` like you do with `client.posts()`
109 | client
110 | .products()
111 | .get()
112 | .then((res) => {
113 | console.log(res.data);
114 | })
115 | .catch((err) => {
116 | console.log('Error: ' + err.message);
117 | });
118 | ```
119 |
120 | ## HTTP Methods
121 |
122 | Client instances also provide access to HTTP methods to access API resources.
123 |
124 | ```js
125 | // HTTP GET
126 | client.get();
127 |
128 | // HTTP POST
129 | client.create();
130 |
131 | // HTTP PATCH
132 | client.update();
133 |
134 | // HTTP DELETE
135 | client.delete();
136 | ```
137 |
138 | Examples
139 |
140 | ```js
141 | // Create post.
142 | const post = client.posts().create({
143 | title: 'Post title',
144 | content: 'Post content
'
145 | });
146 |
147 | // Update post.
148 | client.posts().update(post.id, {
149 | title: 'Post title 2'
150 | });
151 |
152 | // Delete post.
153 | client.posts().delete(post.id);
154 | ```
155 |
156 | ## Params
157 |
158 | You can pass a object with the same name as as the existing params. You can write `per_page` or `perPage` when the param contains a underscore.
159 |
160 | ```js
161 | client
162 | .posts()
163 | .get({
164 | slug: 'hello-world',
165 | perPage: 1 // or per_page
166 | })
167 | .then((res) => {
168 | console.log(res.data);
169 | })
170 | .catch((err) => {
171 | console.log('Error: ' + err.message);
172 | });
173 | ```
174 |
175 | You can also set global params using key/value or object
176 |
177 | ```js
178 | client.param('source', 'yllet');
179 | ```
180 |
181 | All global params can be accessed with `client.params`
182 |
183 | ## Embed data
184 |
185 | WordPress API support embedding of resources and instead of having to provide `_embed=true` as a param on every request we can simpley use `embed()` before any request method.
186 |
187 | More about WordPress API embedding can you read [here](https://developer.wordpress.org/rest-api/using-the-rest-api/linking-and-embedding/#embedding).
188 |
189 | ```js
190 | client
191 | .posts()
192 | .embed()
193 | .get({
194 | slug: 'hello-world'
195 | })
196 | .then((res) => {
197 | console.log(res.data);
198 | })
199 | .catch((err) => {
200 | console.log('Error: ' + err.message);
201 | });
202 | ```
203 |
204 | ## File uploading
205 |
206 | When Uploading a file you should use `client.file(file, [name])` to specify a file or a file buffer to attach to the request with a name (optional).
207 |
208 | Browser example:
209 |
210 | ```js
211 | const file = document.getElementById('my-file').files[0];
212 |
213 | client
214 | .media()
215 | .file(file)
216 | .create({
217 | title: 'Test image'
218 | })
219 | .then((res) => {
220 | console.log(res.data);
221 | })
222 | .catch((err) => {
223 | console.log('Error: ', err);
224 | });
225 | ```
226 |
227 | Node example:
228 |
229 | ```js
230 | import fs from 'fs';
231 |
232 | client
233 | .media()
234 | .file(fs.createReadStream('me.jpg'))
235 | .create({
236 | title: 'Test image'
237 | })
238 | .then((res) => {
239 | console.log(res.data);
240 | })
241 | .catch((err) => {
242 | console.log('Error: ', err);
243 | });
244 | ```
245 |
246 | ## Authentication
247 |
248 | Yllet version 2 offers an header based auth using the WordPress nonce.
249 |
250 | Adding a JavaScript object with `endpoint` and `nonce`
251 |
252 | ```php
253 | wp_localize_script( 'wp-api', 'wpApiSettings', array(
254 | 'endpoint' => esc_url_raw( rest_url() ),
255 | 'nonce' => wp_create_nonce( 'wp_rest' )
256 | ) );
257 | ```
258 |
259 | The client will add `X-WP-Nonce` header when adding `nonce` option.
260 |
261 | ```js
262 | import Client from '@yllet/client';
263 |
264 | const client = new Client({
265 | endpoint: window.wpApiSettings.endpoint,
266 | nonce: window.wpApiSettings.nonce
267 | });
268 | ```
269 |
270 | ## Discover the REST API from a URL
271 |
272 | ```js
273 | import Client from '@yllet/client';
274 |
275 | Client.discover('http://demo.wp-api.org/')
276 | .then((url) => {
277 | console.log(url);
278 | })
279 | .catch((err) => {
280 | console.log('Error: ', err);
281 | });
282 | ```
283 |
284 | ## Middlewares
285 |
286 | Yllet has middlewares since 2.1.0 and can modify transport, add headers, change options or something else. All middlewares runs before the request. It's important to run the `next` function to run the next middleware or the actual request.
287 |
288 | Examples
289 |
290 | ```js
291 | client.use((client, next) => {
292 | client.transport = new CustomTransport();
293 | next();
294 | });
295 |
296 | client.use((client, next) => {
297 | client.header('X-Foo', 'Bar');
298 | next();
299 | });
300 |
301 | client.use((client, next) => {
302 | setTimeout(next, 1000);
303 | });
304 |
305 | client.use(async (client, next) => {
306 | await something();
307 | return next();
308 | });
309 | ```
310 |
311 | ## Transport layers
312 |
313 | Yllet supports different transport layers so you can use your own favorite HTTP client, e.g axios.
314 |
315 | ### Fetch
316 |
317 | To support older browsers we recommend to use [isomorphic-unfetch](https://github.com/developit/unfetch/tree/master/packages/isomorphic-unfetch), a minimal polyfill for fetch which allows for usage in both client and server settings.
318 |
319 | Installation
320 |
321 | ```
322 | npm install --save @yllet/client isomorphic-unfetch
323 | ```
324 |
325 | Usage
326 |
327 | ```js
328 | import 'isomorphic-unfetch';
329 | import Client from '@yllet/client';
330 |
331 | const client = new Client({
332 | endpoint: 'https://demo.wp-api.org/wp-json'
333 | });
334 | ```
335 |
336 | ### Others
337 |
338 | To add a custom transport to the client you just pass a transport class. Yllet don't offer any other transports than fetch right now, but it's kind of easy to build one.
339 |
340 | You can find examples of transports [here](../../examples/transports)
341 |
342 | To use another transport class, just pass it in as a option
343 |
344 | ```js
345 | const client = new Client({
346 | endpoint: 'https://demo.wp-api.org/wp-json/',
347 | transport: new AxiosTransport()
348 | });
349 | ```
350 |
351 | ## React bindings
352 |
353 | To install the package with React bindings
354 |
355 | ```
356 | npm install --save @yllet/react
357 | ```
358 |
359 | ### Provider component
360 |
361 | Yllets React package contains a provider component that you can use like this
362 |
363 | ```js
364 | import React from 'react';
365 | import ReactDOM from 'react-dom';
366 | import App from './App';
367 |
368 | import Client from '@yllet/client';
369 | import { Provider } from '@yllet/react';
370 |
371 | const client = new Client({
372 | endpoint: 'https://demo.wp-api.org/wp-json/'
373 | });
374 |
375 | ReactDOM.render(
376 |
377 |
378 | ,
379 | document.getElementById('root')
380 | );
381 | ```
382 |
383 | In your application component you can use the `withClient` component enhancer to pass along the `client` to your component.
384 |
385 | ```js
386 | import React from 'react';
387 | import { withClient } from '@yllet/react';
388 |
389 | class App extends React.Component {}
390 |
391 | export default withClient(App);
392 | ```
393 |
394 | Then you can use `this.props.client` the same way as if it was a standalone client.
395 |
396 | You can also use `withClientData` to pass the response data or the error from WordPress REST API.
397 |
398 | ```js
399 | import React from 'react';
400 | import { withClientData } from '@yllet/react';
401 |
402 | class Post extends React.Component {}
403 |
404 | export default withClientData((client, props) => {
405 | return client.posts().get(1);
406 | })(Post);
407 | ```
408 |
409 | Then you can use `this.props.data` or `this.props.error` and `this.props.loading`
410 |
411 | ### Hooks
412 |
413 | In version 2 we also add a hook to create a client
414 |
415 | ```js
416 | import React, { useEffect, useState } from 'react';
417 | import { useClient } from '@yllet/react';
418 |
419 | function App() {
420 | const endpoint = 'https://demo.wp-api.org/wp-json/';
421 | const client = useClient({ endpoint });
422 | const [posts, setPosts] = useState([]);
423 |
424 | useEffect(() => {
425 | const fetchPosts = async () => {
426 | const response = await client.posts().get();
427 | setPosts(response);
428 | };
429 | fetchPosts();
430 | }, [client]);
431 |
432 | return (
433 |
434 |
Posts
435 |
436 | {posts.map((p, pi) => (
437 | - {p.title.rendered}
438 | ))}
439 |
440 |
441 | );
442 | }
443 |
444 | export default App;
445 | ```
446 |
--------------------------------------------------------------------------------
/packages/client/src/Client.ts:
--------------------------------------------------------------------------------
1 | import FormData from 'isomorphic-form-data';
2 | import { mergeObjects, isObject, objectKeysToSnakeCase } from '@yllet/support';
3 | import Transport from './Transport';
4 | import type { Options, Middleware, Params } from './Client.types';
5 |
6 | class Client {
7 | /**
8 | * Request config.
9 | *
10 | * @var {object}
11 | */
12 | config: Record = {};
13 |
14 | /**
15 | * File attachment.
16 | *
17 | * @var {FormData}
18 | */
19 | formData: any = undefined;
20 |
21 | /**
22 | * Request middlewares.
23 | *
24 | * @var {array}
25 | */
26 | middlewares: Middleware[] = [];
27 |
28 | /**
29 | * Client options.
30 | *
31 | * @var {object}
32 | */
33 | options: Options = {
34 | config: {},
35 | endpoint: '',
36 | headers: {
37 | 'Content-Type': 'application/json',
38 | },
39 | namespace: 'wp/v2',
40 | nonce: '',
41 | resource: '',
42 | restore: true,
43 | };
44 |
45 | /**
46 | * Request params.
47 | *
48 | * @var {object}
49 | */
50 | params: Params = {};
51 |
52 | /**
53 | * Transport layer.
54 | *
55 | * @var {Transport}
56 | */
57 | transport = new Transport();
58 |
59 | /**
60 | * Client constructor.
61 | *
62 | * @param {string|object} options
63 | */
64 | constructor(options: string | Options = {}) {
65 | if (typeof options === 'string') {
66 | options = {
67 | endpoint: options,
68 | };
69 | }
70 |
71 | this._setupOptions(options);
72 | }
73 |
74 | /**
75 | * Returns real options object.
76 | *
77 | * @param {object} options
78 | *
79 | * @return {object}
80 | */
81 | _setupOptions(options: Options = {}) {
82 | if (!isObject(options)) {
83 | options = this.options;
84 | }
85 |
86 | if (!isObject(options.config)) {
87 | options.config = {
88 | headers: {},
89 | };
90 | }
91 |
92 | // Set middlewares.
93 | this.middlewares = Array.isArray(options.middlewares) ? options.middlewares : [];
94 | delete options.middlewares;
95 |
96 | // Set transport.
97 | this.transport = options.transport ? options.transport : this.transport;
98 | delete options.transport;
99 |
100 | // Merge headers and create config object.
101 | const headers = mergeObjects(
102 | options.config.headers,
103 | mergeObjects(this.options.headers, options.headers || {}),
104 | );
105 | options.config = { ...options.config, headers: { ...headers } };
106 |
107 | // Add nonce if any.
108 | if (options.nonce) {
109 | options.config.headers['X-WP-Nonce'] = options.nonce;
110 | }
111 |
112 | // Merge options.
113 | options = mergeObjects(this.options, options);
114 |
115 | // Delete headers since it's in the config object.
116 | delete options.headers;
117 |
118 | this.options = options;
119 | }
120 |
121 | /**
122 | * Returns full request url.
123 | *
124 | * @param {string} path
125 | *
126 | * @return {string}
127 | */
128 | _getUrl(path: string): string {
129 | const { endpoint, namespace, resource } = this.options;
130 |
131 | const safePath = String(path || '');
132 | const safeEndpoint = endpoint.replace(namespace, '').replace(/\/$/, '') + '/';
133 | const safeResource = resource.replace(/^\/|\/$/g, '');
134 | const safeNamespace = namespace.replace(/^\/|\/$/g, '') + (safeResource || safePath ? '/' : '');
135 |
136 | return (
137 | safeEndpoint + safeNamespace + safeResource + (safeResource && safePath ? '/' : '') + safePath
138 | );
139 | }
140 |
141 | /**
142 | * Returns request params.
143 | *
144 | * @param {object} params
145 | *
146 | * @return {object}
147 | */
148 | _getParams(params: Params): Params {
149 | let merged: Params;
150 | params = isObject(params) ? objectKeysToSnakeCase(params) : {};
151 | merged = { ...this.params, ...params };
152 |
153 | if (this.formData instanceof FormData) {
154 | Object.keys(merged).forEach((key) => {
155 | this.formData.append(key, merged[key]);
156 | });
157 | merged = this.formData;
158 | }
159 |
160 | return merged;
161 | }
162 |
163 | /**
164 | * Run middlewares.
165 | *
166 | * @param {function} last
167 | *
168 | * @return {function}
169 | */
170 | async _runMiddlewares(last: Middleware) {
171 | // eslint-disable-next-line @typescript-eslint/no-this-alias
172 | const self = this;
173 | const { endpoint, namespace, resource } = this.options;
174 | const next = async () => {
175 | const middleware = self.middlewares.shift();
176 |
177 | self.options = {
178 | ...self.options,
179 | namespace,
180 | resource,
181 | endpoint,
182 | };
183 |
184 | if (!middleware) {
185 | return await last.call(this, self, next);
186 | }
187 |
188 | if (typeof middleware === 'function') {
189 | await middleware.call(this, self, next);
190 | }
191 |
192 | return self;
193 | };
194 |
195 | return await next();
196 | }
197 |
198 | /**
199 | * Discover the REST API from a URL.
200 | *
201 | * @param {string} url
202 | *
203 | * @return {Promise}
204 | */
205 | discover(url: string): Promise {
206 | return this.transport
207 | .get(url, {
208 | rest_route: '/',
209 | })
210 | .then((response: Record) => {
211 | if (isObject(response.routes)) {
212 | return response.routes['/']._links.self;
213 | }
214 |
215 | throw new Error('Unable to find the REST API');
216 | });
217 | }
218 |
219 | /**
220 | * Enable embed mode.
221 | *
222 | * @return {Client}
223 | */
224 | embed() {
225 | return this.param('_embed', true);
226 | }
227 |
228 | /**
229 | * Sets the endpoint.
230 | *
231 | * @param {string} endpoint
232 | *
233 | * @return {Client}
234 | */
235 | endpoint(endpoint: string) {
236 | this.options.endpoint = endpoint;
237 | return this;
238 | }
239 |
240 | /**
241 | *
242 | * Specify a file or a file buffer to attach to the request with a name (optional).
243 | *
244 | * @param {string} file
245 | * @param {string} name
246 | *
247 | * @return {Client}
248 | */
249 | file(file: any, name = '') {
250 | const formData = new FormData();
251 | formData.append('file', file);
252 |
253 | this.header('Content-Type', 'multipart/form-data');
254 | this.header('Content-Disposition', `attachment; filename=${name}`);
255 |
256 | this.formData = formData;
257 |
258 | return this;
259 | }
260 |
261 | /**
262 | * Set a single header or headers object.
263 | *
264 | * @param {object|string} headers
265 | * @param {string} value
266 | *
267 | * @return {Client|string}
268 | */
269 | header(key: string | Params, value: any = null) {
270 | let { headers = {} } = this.options.config;
271 |
272 | if (typeof key === 'string' && !value) {
273 | return headers[key];
274 | }
275 |
276 | if (typeof key === 'string') {
277 | headers[key] = value;
278 | } else {
279 | headers = { ...headers, ...key };
280 | }
281 |
282 | this.options.config = { ...this.options.config, headers: { ...headers } };
283 |
284 | return this;
285 | }
286 |
287 | /**
288 | * Modify namespace that is used.
289 | *
290 | * @param {string} namespace
291 | *
292 | * @return {Client}
293 | */
294 | namespace(namespace: string) {
295 | this.options.namespace = namespace;
296 | return this;
297 | }
298 |
299 | /**
300 | * Get the categories resource.
301 | *
302 | * @return {Client}
303 | */
304 | categories() {
305 | return this.resource('categories');
306 | }
307 |
308 | /**
309 | * Get the comments resource.
310 | *
311 | * @return {Client}
312 | */
313 | comments() {
314 | return this.resource('comments');
315 | }
316 |
317 | /**
318 | * Get the media resource.
319 | *
320 | * @return {Client}
321 | */
322 | media() {
323 | return this.resource('media');
324 | }
325 |
326 | /**
327 | * Get the statuses resource.
328 | *
329 | * @return {Client}
330 | */
331 | statuses() {
332 | return this.resource('statuses');
333 | }
334 |
335 | /**
336 | * Get the pages resource.
337 | *
338 | * @return {Client}
339 | */
340 | pages() {
341 | return this.resource('pages');
342 | }
343 |
344 | /**
345 | * Get the posts resource.
346 | *
347 | * @return {Client}
348 | */
349 | posts() {
350 | return this.resource('posts');
351 | }
352 |
353 | /**
354 | * Get the settings resource.
355 | *
356 | * @return {Client}
357 | */
358 | settings() {
359 | return this.resource('settings');
360 | }
361 |
362 | /**
363 | * Get the tags resource.
364 | *
365 | * @return {Client}
366 | */
367 | tags() {
368 | return this.resource('tags');
369 | }
370 |
371 | /**
372 | * Get the taxonomies resource.
373 | *
374 | * @return {Client}
375 | */
376 | taxonomies() {
377 | return this.resource('taxonomies');
378 | }
379 |
380 | /**
381 | * Get the types resource.
382 | *
383 | * @return {Client}
384 | */
385 | types() {
386 | return this.resource('types');
387 | }
388 |
389 | /**
390 | * Get the users resource.
391 | *
392 | * @return {Client}
393 | */
394 | users() {
395 | return this.resource('users');
396 | }
397 |
398 | /**
399 | * Get the search resource.
400 | *
401 | * @return {Client}
402 | */
403 | search() {
404 | return this.resource('search');
405 | }
406 |
407 | /**
408 | * Sets the resource path.
409 | *
410 | * @param {string} resource
411 | *
412 | * @return {Client}
413 | */
414 | resource(resource: string) {
415 | this.options.resource = resource;
416 | return this;
417 | }
418 |
419 | /**
420 | * Set/Get global param.
421 | *
422 | * @param {string|object} key
423 | * @param {object} value
424 | *
425 | * @return {Client|object}
426 | */
427 | param(key: string | Params, value: any = null) {
428 | if (typeof key === 'string' && !value) {
429 | return this.params[key];
430 | }
431 |
432 | if (typeof key === 'string') {
433 | this.params[key] = value;
434 | } else {
435 | this.params = { ...this.params, ...key };
436 | }
437 |
438 | return this;
439 | }
440 |
441 | /**
442 | * Fetch content by slug.
443 | *
444 | * @param {string} slug
445 | * @param {object} params
446 | *
447 | * @return {object}
448 | */
449 | slug(slug: string, params: Params = {}) {
450 | return this.request('get', {
451 | ...params,
452 | per_page: 1,
453 | slug,
454 | }).then((res) => res[0]);
455 | }
456 |
457 | /**
458 | * Send GET request.
459 | *
460 | * @param {string} path
461 | * @param {object} params
462 | *
463 | * @return {Promise}
464 | */
465 | get(path = '', params: Params = {}): Promise {
466 | return this.request('get', path, params);
467 | }
468 |
469 | /**
470 | * Send Create/POST request.
471 | *
472 | * @param {string} path
473 | * @param {object} params
474 | *
475 | * @return {Promise}
476 | */
477 | create(path = '', params: Params = {}): Promise {
478 | return this.request('post', path, params);
479 | }
480 |
481 | /**
482 | * Send Update/PUT request.
483 | *
484 | * @param {string} path
485 | * @param {object} params
486 | *
487 | * @return {Promise}
488 | */
489 | update(path = '', params: Params = {}): Promise {
490 | return this.request('put', path, params);
491 | }
492 |
493 | /**
494 | * Send Delete request.
495 | *
496 | * @param {string} path
497 | * @param {object} params
498 | *
499 | * @return {Promise}
500 | */
501 | delete(path = '', params: Params = {}): Promise {
502 | return this.request('delete', path, params);
503 | }
504 |
505 | /**
506 | * Send API request
507 | *
508 | * @param {string} verb
509 | * @param {string} path
510 | * @param {object} params
511 | *
512 | * @return {Promise}
513 | */
514 | request(verb: string, path: string | Params = '', params: Params = {}): Promise {
515 | if (isObject(path)) {
516 | params = path as any;
517 | path = '';
518 | }
519 |
520 | return new Promise((resolve) => {
521 | this._runMiddlewares(() => {
522 | const response = this.transport[verb.toLowerCase()](
523 | this._getUrl(path as string),
524 | this._getParams(params),
525 | this.options.config,
526 | );
527 |
528 | resolve(response);
529 | });
530 | });
531 | }
532 |
533 | /**
534 | * Add middlewares that should be runned before request.
535 | *
536 | * @param {array|function} fn
537 | */
538 | use(fn: Middleware[] | Middleware) {
539 | if (!Array.isArray(fn)) {
540 | fn = [fn];
541 | }
542 |
543 | this.middlewares = this.middlewares.concat(fn);
544 |
545 | return this;
546 | }
547 | }
548 |
549 | export default Client;
550 |
--------------------------------------------------------------------------------
/packages/client/tsconfig.tsbuildinfo:
--------------------------------------------------------------------------------
1 | {"program":{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/globals.global.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/ts3.6/base.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/base.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/form-data/index.d.ts","../../node_modules/@types/isomorphic-form-data/index.d.ts","./src/transport.ts","./src/index.types.ts","./src/index.ts","../../node_modules/@types/aria-query/index.d.ts","../../node_modules/@babel/types/lib/index.d.ts","../../node_modules/@types/babel__generator/index.d.ts","../../node_modules/@babel/parser/typings/babel-parser.d.ts","../../node_modules/@types/babel__template/index.d.ts","../../node_modules/@types/babel__traverse/index.d.ts","../../node_modules/@types/babel__core/index.d.ts","../../node_modules/@types/graceful-fs/index.d.ts","../../node_modules/@types/invariant/index.d.ts","../../node_modules/@types/istanbul-lib-coverage/index.d.ts","../../node_modules/@types/istanbul-lib-report/index.d.ts","../../node_modules/@types/istanbul-reports/index.d.ts","../../node_modules/jest-diff/build/cleanupsemantic.d.ts","../../node_modules/pretty-format/build/types.d.ts","../../node_modules/pretty-format/build/index.d.ts","../../node_modules/jest-diff/build/types.d.ts","../../node_modules/jest-diff/build/difflines.d.ts","../../node_modules/jest-diff/build/printdiffs.d.ts","../../node_modules/jest-diff/build/index.d.ts","../../node_modules/@types/jest/index.d.ts","../../node_modules/@types/json5/index.d.ts","../../node_modules/@types/minimatch/index.d.ts","../../node_modules/@types/minimist/index.d.ts","../../node_modules/@types/normalize-package-data/index.d.ts","../../node_modules/@types/parse-json/index.d.ts","../../node_modules/@types/prettier/index.d.ts","../../node_modules/@types/prop-types/index.d.ts","../../node_modules/@types/react/global.d.ts","../../node_modules/csstype/index.d.ts","../../node_modules/@types/scheduler/tracing.d.ts","../../node_modules/@types/react/index.d.ts","../../node_modules/@types/react-dom/index.d.ts","../../node_modules/@types/react-test-renderer/index.d.ts","../../node_modules/@types/scheduler/index.d.ts","../../node_modules/@types/stack-utils/index.d.ts","../../node_modules/@types/testing-library__jest-dom/index.d.ts","../../node_modules/@types/yargs-parser/index.d.ts","../../node_modules/@types/yargs/index.d.ts"],"fileInfos":[{"version":"6adbf5efd0e374ff5f427a4f26a5a413e9734eee5067a0e86da69aea41910b52","affectsGlobalScope":true},"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06",{"version":"abba1071bfd89e55e88a054b0c851ea3e8a494c340d0f3fab19eb18f6afb0c9e","affectsGlobalScope":true},{"version":"d8996609230d17e90484a2dd58f22668f9a05a3bfe00bfb1d6271171e54a31fb","affectsGlobalScope":true},{"version":"43fb1d932e4966a39a41b464a12a81899d9ae5f2c829063f5571b6b87e6d2f9c","affectsGlobalScope":true},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true},{"version":"4378fc8122ec9d1a685b01eb66c46f62aba6b239ca7228bb6483bcf8259ee493","affectsGlobalScope":true},{"version":"0d5f52b3174bee6edb81260ebcd792692c32c81fd55499d69531496f3f2b25e7","affectsGlobalScope":true},{"version":"810627a82ac06fb5166da5ada4159c4ec11978dfbb0805fe804c86406dab8357","affectsGlobalScope":true},{"version":"62d80405c46c3f4c527ee657ae9d43fda65a0bf582292429aea1e69144a522a6","affectsGlobalScope":true},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true},{"version":"75ec0bdd727d887f1b79ed6619412ea72ba3c81d92d0787ccb64bab18d261f14","affectsGlobalScope":true},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true},{"version":"12a310447c5d23c7d0d5ca2af606e3bd08afda69100166730ab92c62999ebb9d","affectsGlobalScope":true},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true},{"version":"1b3fe904465430e030c93239a348f05e1be80640d91f2f004c3512c2c2c89f34","affectsGlobalScope":true},{"version":"10bbdc1981b8d9310ee75bfac28ee0477bb2353e8529da8cff7cb26c409cb5e8","affectsGlobalScope":true},{"version":"25b4a0c4fab47c373ee49df4c239826ee3430019fc0c1b5e59edc3e398b7468d","affectsGlobalScope":true},"d20f08527645f62facb2d66c2b7bd31ea964b59c897d00bddb1efe8c13890b72","5726b5ce952dc5beaeb08d5f64236632501568a54a390363d2339ba1dc5393b1","674bedbfd2004e233e2a266a3d2286e524f0d58787a98522d834d6ccda1d215a","714637d594e1a38a075091fe464ca91c6abc0b154784b4287f6883200e28ccef",{"version":"23edba5f47d3409810c563fe8034ae2c59e718e1ef8570f4152ccdde1915a096","affectsGlobalScope":true},"0e9c55f894ca2d9cf63b5b0d43a8cec1772dd560233fd16275bc7a485eb82f83","d53b352a01645c470a0d8c31bf290ba791fc28ade0ce187a4a50f5c2f826f75e","5f0a09de75bd965c21dc6d73671ba88830272f9ed62897bb0aa9754b369b1eed","2b34e7fcba9e1f24e7f54ba5c8be5a8895b0b8b444ccf6548e04acdee0899317",{"version":"06d2be99c3dd2ff52114d02ee443ba486ab482423df1941d3c97d6a92e924d70","affectsGlobalScope":true},{"version":"bfd4f140c07091b5e8a963c89e6fa3f44b6cfcbc11471b465cf63e2d020ad0eb","affectsGlobalScope":true},"a106a0bea088b70879ac88ff606dc253c0cc474ea05ad3a282b8bfb1091ae576","c98ce957db9eebd75f53edda3f6893e05ab2d2283b5667b18e31bcdb6427ed10","1f08bd8305d4a789a68f71ab622156dfff993aa51a2aa58b9ccf166cc6f9fcf7","9aff68f1b847b846d3d50a58c9f8f99389bedd0258d1b1c201f11b97ecfd36f8","1978992206803f5761e99e893d93b25abc818c5fe619674fdf2ae02b29f641ba","05fbe81f09fc455a2c343d2458d2b3c600c90b92b22926be765ee79326be9466","8e7d6dae9e19bbe47600dcfd4418db85b30ae7351474ea0aad5e628f9845d340","f20ea392f7f27feb7a90e5a24319a4e365b07bf83c39a547711fe7ff9df68657","32542c4660ecda892a333a533feedba31738ee538ef6a78eb73af647137bc3fc","0ecacea5047d1a7d350e7049dbd22f26435be5e8736a81a56afec5b3264db1ca","ffcb4ebde21f83370ed402583888b28651d2eb7f05bfec9482eb46d82adedd7f",{"version":"06c004006016a51c4d1855527a523562c329dc44c473931c65f10373281f730e","affectsGlobalScope":true},"a7b43c69f9602d198825e403ee34e5d64f83c48b391b2897e8c0e6f72bca35f8","f4a3fc4efc6944e7b7bd4ccfa45e0df68b6359808e6cf9d061f04fd964a7b2d3","73cad675aead7a2c05cf934e7e700c61d84b2037ac1d576c3f751199b25331da","8c3137ba3583ec18484429ec1c8eff89efdc42730542f157b38b102fdccc0c71","d84300d886b45a198c346158e4ff7ae361cc7bc1c3deab44afb3db7de56b5d25","94ca7beec4e274d32362b54e0133152f7b4be9487db7b005070c03880b6363aa","2d713cbcbd5bcc38d91546eaeea7bb1c8686dc4a2995a28556d957b1b9de11d9","bbf21f210782db4193359010a4710786add43e3b50aa42fc0d371f45b4e4d8d3","0b7733d83619ac4e3963e2a9f7c75dc1e9af6850cb2354c9554977813092c10a","3ce933f0c3955f67f67eb7d6b5c83c2c54a18472c1d6f2bb651e51dd40c84837","631e96db896d645f7132c488ad34a16d71fd2be9f44696f8c98289ee1c8cbfa9","2c77230d381cba81eb6f87cda2fbfff6c0427c6546c2e2590110effff37c58f7","da86ee9a2f09a4583db1d5e37815894967e1f694ad9f3c25e84e0e4d40411e14","141a943e5690105898a67537a470f70b56d0e183441b56051d929e902376b7b2","ddc086b1adac44e2fccf55422da1e90fa970e659d77f99712422a421564b4877","515ef1d99036ff0dafa5bf738e02222edea94e0d97a0aa0ff277ac5e96b57977",{"version":"2708349d5a11a5c2e5f3a0765259ebe7ee00cdcc8161cb9990cb4910328442a1","affectsGlobalScope":true},"780058f4a804c8bdcdd2f60e7af64b2bc57d149c1586ee3db732a84d659a50bf","ae68a04912ee5a0f589276f9ec60b095f8c40d48128a4575b3fdd7d93806931c","19d580a3b42ad5caeaee266ae958260e23f2df0549ee201c886c8bd7a4f01d4e","e61a21e9418f279bc480394a94d1581b2dee73747adcbdef999b6737e34d721b","9c4c395e927045b324877acdc4bfb95f128f36bc9f073266a2f0342495075a4f","e91ad231af87f864b3f07cd0e39b1cf6c133988156f087c1c3ccb0a5491c9115","4ebd5321ca0246abcf379398077a0886b8f0e324dabd4d7aac4dfb69dc83dad2","f7250885f826e127b44ec9fee8201049f529f5199ed3ffff5f3136b337c244d8","9c160fccfe02c9cbfb087b2bf43a33a2aee1379c4b07fc262f9c35d986719d87","99f7128e39d438d12ed8f15d78128559e63d1ade552b3afcb215149aaa0d7e0e","5024433f8da3a7968f6d12cffd32f2cefae4442a9ad1c965fa2d23342338b700","272c2dac4baaf7fdd2d7efeef0fa2547af54cc21883c5e138b8c4d1661697a54","b25c5f2970d06c729f464c0aeaa64b1a5b5f1355aa93554bb5f9c199b8624b1e","64b867c61effed7b5bc0cc06b3d8eac23b067a3fba581fc7d3c292fa593e6a45","3051751533eee92572241b3cef28333212401408c4e7aa21718714b793c0f4ed","691aea9772797ca98334eb743e7686e29325b02c6931391bcee4cc7bf27a9f3b","d0b0a00cf31968a33baeaadf974ce4e5e7edf58cea5288765293f41ba5e72b3a","3ebae8c00411116a66fca65b08228ea0cf0b72724701f9b854442100aab55aba","6acf8a984c2728906edeba2098c5c51f44a4520bc4a48c65b973bd785537178f","de18acda71730bac52f4b256ce7511bb56cc21f6f114c59c46782eff2f632857","7eb06594824ada538b1d8b48c3925a83e7db792f47a081a62cf3e5c4e23cf0ee","905c3e8f7ddaa6c391b60c05b2f4c3931d7127ad717a080359db3df510b7bdab","d8aab31ba8e618cc3eea10b0945de81cb93b7e8150a013a482332263b9305322","462bccdf75fcafc1ae8c30400c9425e1a4681db5d605d1a0edb4f990a54d8094","5923d8facbac6ecf7c84739a5c701a57af94a6f6648d6229a6c768cf28f0f8cb","7adecb2c3238794c378d336a8182d4c3dd2c4fa6fa1785e2797a3db550edea62","dc12dc0e5aa06f4e1a7692149b78f89116af823b9e1f1e4eae140cd3e0e674e6","1bfc6565b90c8771615cd8cfcf9b36efc0275e5e83ac7d9181307e96eb495161","8a8a96898906f065f296665e411f51010b51372fa260d5373bf9f64356703190",{"version":"e9f2cdc4e98e73a606ff68c470a8cb4f23cd638c47649d71b90a2d9413102080","affectsGlobalScope":true},"96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","95c22bc19835e28e2e524a4bb8898eb5f2107b640d7279a6d3aade261916bbf2","e437d83044ba17246a861aa9691aa14223ff4a9d6f338ab1269c41c758586a88","c9ad058b2cc9ce6dc2ed92960d6d009e8c04bef46d3f5312283debca6869f613","2b8264b2fefd7367e0f20e2c04eed5d3038831fe00f5efbc110ff0131aab899b","9d9e658d1d5b805562749ce383ef8c67ccb796394d8734d9c138788d7dab6ee3","f7b46d22a307739c145e5fddf537818038fdfffd580d79ed717f4d4d37249380",{"version":"ecf78e637f710f340ec08d5d92b3f31b134a46a4fcf2e758690d8c46ce62cba6","affectsGlobalScope":true},"381899b8d1d4c1be716f18cb5242ba39f66f4b1e31d45af62a32a99f8edcb39d","f5a8b384f182b3851cec3596ccc96cb7464f8d3469f48c74bf2befb782a19de5",{"version":"1bc82f5b3bb93df76d19730c84467b0b346187198537135d63a672956f323720","affectsGlobalScope":true},"45a63e17814c570ea59407f231ef9c561510bd6edb36f17479b09b44619496c6","60aaac5fb1858fbd4c4eb40e01706eb227eed9eca5c665564bd146971280dbd3","74b0245c42990ed8a849df955db3f4362c81b13f799ebc981b7bec2d5b414a57","c6c4fea9acc55d5e38ff2b70d57ab0b5cdbd08f8bc5d7a226e322cea128c5b57",{"version":"dd4d769260a2b8cf19f0d2457f3142b24f083237932b0d1edb5fd728a989c8bd","affectsGlobalScope":true},"3bdd93ec24853e61bfa4c63ebaa425ff3e474156e87a47d90122e1d8cc717c1f","6ba73232c9d3267ca36ddb83e335d474d2c0e167481e3dec416c782894e11438"],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"emitDeclarationOnly":false,"emitDecoratorMetadata":true,"esModuleInterop":true,"experimentalDecorators":true,"noImplicitReturns":true,"noUnusedLocals":true,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":true,"suppressImplicitAnyIndexErrors":true,"target":1},"fileIdsList":[[81],[81,82,83,84,85],[81,83],[41,74],[75],[89],[90],[94,98],[72],[30],[71,72],[31],[32,40,41,48,57],[32,33,40,48],[64],[35,36,41,49],[36,57],[37,38,40,48],[38],[39,40],[40],[40,41,42,57,63],[41,42],[43,48,57,63],[40,41,43,44,48,57,60,63],[43,45,60,63],[73],[40,46],[47,63],[38,40,48,57],[49],[50],[30,51],[62],[53],[54],[40,55],[55,56,64,66],[40,57],[58],[59],[48,60],[61],[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70],[48,62],[54,63],[57,65],[66],[70],[40,42,57,63,66,67],[57,68],[110],[106,107,108,109],[99],[116],[43,57,74],[92,95],[92,95,96,97],[94],[93],[76,77,78],[79],[76]],"referencedMap":[[83,1],[86,2],[82,1],[84,3],[85,1],[87,4],[76,5],[90,6],[91,7],[99,8],[72,9],[30,10],[73,11],[31,12],[32,13],[33,14],[34,15],[35,16],[36,17],[37,18],[38,19],[39,20],[40,21],[41,22],[42,23],[43,24],[44,25],[45,26],[74,27],[46,28],[47,29],[48,30],[49,31],[50,32],[51,33],[52,34],[53,35],[54,36],[55,37],[56,38],[57,39],[58,40],[59,41],[60,42],[61,43],[71,44],[62,45],[63,46],[64,15],[65,47],[66,48],[70,49],[67,50],[68,51],[111,52],[112,52],[110,53],[115,54],[117,55],[75,56],[96,57],[98,58],[97,57],[95,59],[94,60],[79,61],[78,62],[77,63]],"exportedModulesMap":[[83,1],[86,2],[82,1],[84,3],[85,1],[87,4],[76,5],[90,6],[91,7],[99,8],[72,9],[30,10],[73,11],[31,12],[32,13],[33,14],[34,15],[35,16],[36,17],[37,18],[38,19],[39,20],[40,21],[41,22],[42,23],[43,24],[44,25],[45,26],[74,27],[46,28],[47,29],[48,30],[49,31],[50,32],[51,33],[52,34],[53,35],[54,36],[55,37],[56,38],[57,39],[58,40],[59,41],[60,42],[61,43],[71,44],[62,45],[63,46],[64,15],[65,47],[66,48],[70,49],[67,50],[68,51],[111,52],[112,52],[110,53],[115,54],[117,55],[75,56],[96,57],[98,58],[97,57],[95,59],[94,60],[79,61],[78,62],[77,63]],"semanticDiagnosticsPerFile":[83,81,80,86,82,84,85,87,88,76,89,90,91,99,100,101,102,72,30,73,31,32,33,34,35,36,37,38,39,40,41,42,29,69,43,44,45,74,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,71,62,63,64,65,66,70,67,68,103,104,105,106,111,112,107,110,113,109,114,115,116,117,108,75,92,96,98,97,95,94,93,6,8,7,2,9,10,11,12,13,14,15,16,3,4,20,17,18,19,21,22,23,5,24,25,26,27,1,28,79,78,77]},"version":"4.5.2"}
2 |
--------------------------------------------------------------------------------
/examples/next/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-example",
3 | "version": "0.1.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "next-example",
9 | "version": "0.1.0",
10 | "dependencies": {
11 | "@yllet/react": "^3.0.1",
12 | "next": "^12.1.0",
13 | "react": "^17.0.2",
14 | "react-dom": "^17.0.2"
15 | }
16 | },
17 | "node_modules/@next/env": {
18 | "version": "12.1.0",
19 | "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz",
20 | "integrity": "sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ=="
21 | },
22 | "node_modules/@next/swc-android-arm64": {
23 | "version": "12.1.0",
24 | "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz",
25 | "integrity": "sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==",
26 | "cpu": [
27 | "arm64"
28 | ],
29 | "optional": true,
30 | "os": [
31 | "android"
32 | ],
33 | "engines": {
34 | "node": ">= 10"
35 | }
36 | },
37 | "node_modules/@next/swc-darwin-arm64": {
38 | "version": "12.1.0",
39 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz",
40 | "integrity": "sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==",
41 | "cpu": [
42 | "arm64"
43 | ],
44 | "optional": true,
45 | "os": [
46 | "darwin"
47 | ],
48 | "engines": {
49 | "node": ">= 10"
50 | }
51 | },
52 | "node_modules/@next/swc-darwin-x64": {
53 | "version": "12.1.0",
54 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz",
55 | "integrity": "sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==",
56 | "cpu": [
57 | "x64"
58 | ],
59 | "optional": true,
60 | "os": [
61 | "darwin"
62 | ],
63 | "engines": {
64 | "node": ">= 10"
65 | }
66 | },
67 | "node_modules/@next/swc-linux-arm-gnueabihf": {
68 | "version": "12.1.0",
69 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz",
70 | "integrity": "sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==",
71 | "cpu": [
72 | "arm"
73 | ],
74 | "optional": true,
75 | "os": [
76 | "linux"
77 | ],
78 | "engines": {
79 | "node": ">= 10"
80 | }
81 | },
82 | "node_modules/@next/swc-linux-arm64-gnu": {
83 | "version": "12.1.0",
84 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz",
85 | "integrity": "sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==",
86 | "cpu": [
87 | "arm64"
88 | ],
89 | "optional": true,
90 | "os": [
91 | "linux"
92 | ],
93 | "engines": {
94 | "node": ">= 10"
95 | }
96 | },
97 | "node_modules/@next/swc-linux-arm64-musl": {
98 | "version": "12.1.0",
99 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz",
100 | "integrity": "sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==",
101 | "cpu": [
102 | "arm64"
103 | ],
104 | "optional": true,
105 | "os": [
106 | "linux"
107 | ],
108 | "engines": {
109 | "node": ">= 10"
110 | }
111 | },
112 | "node_modules/@next/swc-linux-x64-gnu": {
113 | "version": "12.1.0",
114 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz",
115 | "integrity": "sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==",
116 | "cpu": [
117 | "x64"
118 | ],
119 | "optional": true,
120 | "os": [
121 | "linux"
122 | ],
123 | "engines": {
124 | "node": ">= 10"
125 | }
126 | },
127 | "node_modules/@next/swc-linux-x64-musl": {
128 | "version": "12.1.0",
129 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz",
130 | "integrity": "sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==",
131 | "cpu": [
132 | "x64"
133 | ],
134 | "optional": true,
135 | "os": [
136 | "linux"
137 | ],
138 | "engines": {
139 | "node": ">= 10"
140 | }
141 | },
142 | "node_modules/@next/swc-win32-arm64-msvc": {
143 | "version": "12.1.0",
144 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz",
145 | "integrity": "sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==",
146 | "cpu": [
147 | "arm64"
148 | ],
149 | "optional": true,
150 | "os": [
151 | "win32"
152 | ],
153 | "engines": {
154 | "node": ">= 10"
155 | }
156 | },
157 | "node_modules/@next/swc-win32-ia32-msvc": {
158 | "version": "12.1.0",
159 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz",
160 | "integrity": "sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==",
161 | "cpu": [
162 | "ia32"
163 | ],
164 | "optional": true,
165 | "os": [
166 | "win32"
167 | ],
168 | "engines": {
169 | "node": ">= 10"
170 | }
171 | },
172 | "node_modules/@next/swc-win32-x64-msvc": {
173 | "version": "12.1.0",
174 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz",
175 | "integrity": "sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==",
176 | "cpu": [
177 | "x64"
178 | ],
179 | "optional": true,
180 | "os": [
181 | "win32"
182 | ],
183 | "engines": {
184 | "node": ">= 10"
185 | }
186 | },
187 | "node_modules/@yllet/client": {
188 | "version": "3.0.1",
189 | "resolved": "https://registry.npmjs.org/@yllet/client/-/client-3.0.1.tgz",
190 | "integrity": "sha512-ktS3gUIh/CPbbkhvrIxQ40Ws2YdBNiOZKcLOJKdsZnnfEWNus9CUUMUV/8Ev4a1TI1N6WVnvwgMNciiuwdWR1Q==",
191 | "dependencies": {
192 | "@yllet/support": "^3.0.1",
193 | "isomorphic-form-data": "^2.0.0"
194 | }
195 | },
196 | "node_modules/@yllet/react": {
197 | "version": "3.0.1",
198 | "resolved": "https://registry.npmjs.org/@yllet/react/-/react-3.0.1.tgz",
199 | "integrity": "sha512-cKlR21US/uR1HOlsZRJBBmk8dcMiufPIcL4Oukm0PLNHEgDL04C75kbzW8DRQlme4vH1mcI1WUPNb8ulBafAhA==",
200 | "dependencies": {
201 | "@yllet/client": "^3.0.1",
202 | "invariant": "^2.2.4",
203 | "prop-types": "^15.7.2"
204 | },
205 | "peerDependencies": {
206 | "react": "*"
207 | }
208 | },
209 | "node_modules/@yllet/support": {
210 | "version": "3.0.1",
211 | "resolved": "https://registry.npmjs.org/@yllet/support/-/support-3.0.1.tgz",
212 | "integrity": "sha512-NGbwwlgt8CK0RiR+rzj9ak3ikUaL4M7k9ebnEHbjlLPRfiufBy/1tUA3obaUYms3p/SI8J0it0HEUn7UXQmMzg=="
213 | },
214 | "node_modules/asynckit": {
215 | "version": "0.4.0",
216 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
217 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
218 | },
219 | "node_modules/caniuse-lite": {
220 | "version": "1.0.30001303",
221 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz",
222 | "integrity": "sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ==",
223 | "funding": {
224 | "type": "opencollective",
225 | "url": "https://opencollective.com/browserslist"
226 | }
227 | },
228 | "node_modules/combined-stream": {
229 | "version": "1.0.8",
230 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
231 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
232 | "dependencies": {
233 | "delayed-stream": "~1.0.0"
234 | },
235 | "engines": {
236 | "node": ">= 0.8"
237 | }
238 | },
239 | "node_modules/delayed-stream": {
240 | "version": "1.0.0",
241 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
242 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
243 | "engines": {
244 | "node": ">=0.4.0"
245 | }
246 | },
247 | "node_modules/form-data": {
248 | "version": "2.5.1",
249 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
250 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
251 | "dependencies": {
252 | "asynckit": "^0.4.0",
253 | "combined-stream": "^1.0.6",
254 | "mime-types": "^2.1.12"
255 | },
256 | "engines": {
257 | "node": ">= 0.12"
258 | }
259 | },
260 | "node_modules/invariant": {
261 | "version": "2.2.4",
262 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
263 | "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
264 | "dependencies": {
265 | "loose-envify": "^1.0.0"
266 | }
267 | },
268 | "node_modules/isomorphic-form-data": {
269 | "version": "2.0.0",
270 | "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-2.0.0.tgz",
271 | "integrity": "sha512-TYgVnXWeESVmQSg4GLVbalmQ+B4NPi/H4eWxqALKj63KsUrcu301YDjBqaOw3h+cbak7Na4Xyps3BiptHtxTfg==",
272 | "dependencies": {
273 | "form-data": "^2.3.2"
274 | }
275 | },
276 | "node_modules/js-tokens": {
277 | "version": "4.0.0",
278 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
279 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
280 | },
281 | "node_modules/loose-envify": {
282 | "version": "1.4.0",
283 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
284 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
285 | "dependencies": {
286 | "js-tokens": "^3.0.0 || ^4.0.0"
287 | },
288 | "bin": {
289 | "loose-envify": "cli.js"
290 | }
291 | },
292 | "node_modules/mime-db": {
293 | "version": "1.51.0",
294 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
295 | "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
296 | "engines": {
297 | "node": ">= 0.6"
298 | }
299 | },
300 | "node_modules/mime-types": {
301 | "version": "2.1.34",
302 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
303 | "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
304 | "dependencies": {
305 | "mime-db": "1.51.0"
306 | },
307 | "engines": {
308 | "node": ">= 0.6"
309 | }
310 | },
311 | "node_modules/nanoid": {
312 | "version": "3.2.0",
313 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
314 | "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
315 | "bin": {
316 | "nanoid": "bin/nanoid.cjs"
317 | },
318 | "engines": {
319 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
320 | }
321 | },
322 | "node_modules/next": {
323 | "version": "12.1.0",
324 | "resolved": "https://registry.npmjs.org/next/-/next-12.1.0.tgz",
325 | "integrity": "sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==",
326 | "dependencies": {
327 | "@next/env": "12.1.0",
328 | "caniuse-lite": "^1.0.30001283",
329 | "postcss": "8.4.5",
330 | "styled-jsx": "5.0.0",
331 | "use-subscription": "1.5.1"
332 | },
333 | "bin": {
334 | "next": "dist/bin/next"
335 | },
336 | "engines": {
337 | "node": ">=12.22.0"
338 | },
339 | "optionalDependencies": {
340 | "@next/swc-android-arm64": "12.1.0",
341 | "@next/swc-darwin-arm64": "12.1.0",
342 | "@next/swc-darwin-x64": "12.1.0",
343 | "@next/swc-linux-arm-gnueabihf": "12.1.0",
344 | "@next/swc-linux-arm64-gnu": "12.1.0",
345 | "@next/swc-linux-arm64-musl": "12.1.0",
346 | "@next/swc-linux-x64-gnu": "12.1.0",
347 | "@next/swc-linux-x64-musl": "12.1.0",
348 | "@next/swc-win32-arm64-msvc": "12.1.0",
349 | "@next/swc-win32-ia32-msvc": "12.1.0",
350 | "@next/swc-win32-x64-msvc": "12.1.0"
351 | },
352 | "peerDependencies": {
353 | "fibers": ">= 3.1.0",
354 | "node-sass": "^6.0.0 || ^7.0.0",
355 | "react": "^17.0.2 || ^18.0.0-0",
356 | "react-dom": "^17.0.2 || ^18.0.0-0",
357 | "sass": "^1.3.0"
358 | },
359 | "peerDependenciesMeta": {
360 | "fibers": {
361 | "optional": true
362 | },
363 | "node-sass": {
364 | "optional": true
365 | },
366 | "sass": {
367 | "optional": true
368 | }
369 | }
370 | },
371 | "node_modules/object-assign": {
372 | "version": "4.1.1",
373 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
374 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
375 | "engines": {
376 | "node": ">=0.10.0"
377 | }
378 | },
379 | "node_modules/picocolors": {
380 | "version": "1.0.0",
381 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
382 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
383 | },
384 | "node_modules/postcss": {
385 | "version": "8.4.5",
386 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
387 | "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
388 | "dependencies": {
389 | "nanoid": "^3.1.30",
390 | "picocolors": "^1.0.0",
391 | "source-map-js": "^1.0.1"
392 | },
393 | "engines": {
394 | "node": "^10 || ^12 || >=14"
395 | },
396 | "funding": {
397 | "type": "opencollective",
398 | "url": "https://opencollective.com/postcss/"
399 | }
400 | },
401 | "node_modules/prop-types": {
402 | "version": "15.7.2",
403 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
404 | "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
405 | "dependencies": {
406 | "loose-envify": "^1.4.0",
407 | "object-assign": "^4.1.1",
408 | "react-is": "^16.8.1"
409 | }
410 | },
411 | "node_modules/react": {
412 | "version": "17.0.2",
413 | "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
414 | "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
415 | "dependencies": {
416 | "loose-envify": "^1.1.0",
417 | "object-assign": "^4.1.1"
418 | },
419 | "engines": {
420 | "node": ">=0.10.0"
421 | }
422 | },
423 | "node_modules/react-dom": {
424 | "version": "17.0.2",
425 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
426 | "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
427 | "dependencies": {
428 | "loose-envify": "^1.1.0",
429 | "object-assign": "^4.1.1",
430 | "scheduler": "^0.20.2"
431 | },
432 | "peerDependencies": {
433 | "react": "17.0.2"
434 | }
435 | },
436 | "node_modules/react-is": {
437 | "version": "16.8.6",
438 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
439 | "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
440 | },
441 | "node_modules/scheduler": {
442 | "version": "0.20.2",
443 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
444 | "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
445 | "dependencies": {
446 | "loose-envify": "^1.1.0",
447 | "object-assign": "^4.1.1"
448 | }
449 | },
450 | "node_modules/source-map-js": {
451 | "version": "1.0.2",
452 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
453 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
454 | "engines": {
455 | "node": ">=0.10.0"
456 | }
457 | },
458 | "node_modules/styled-jsx": {
459 | "version": "5.0.0",
460 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.0.tgz",
461 | "integrity": "sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA==",
462 | "engines": {
463 | "node": ">= 12.0.0"
464 | },
465 | "peerDependencies": {
466 | "react": ">= 16.8.0 || 17.x.x || 18.x.x"
467 | },
468 | "peerDependenciesMeta": {
469 | "@babel/core": {
470 | "optional": true
471 | },
472 | "babel-plugin-macros": {
473 | "optional": true
474 | }
475 | }
476 | },
477 | "node_modules/use-subscription": {
478 | "version": "1.5.1",
479 | "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz",
480 | "integrity": "sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==",
481 | "dependencies": {
482 | "object-assign": "^4.1.1"
483 | },
484 | "peerDependencies": {
485 | "react": "^16.8.0 || ^17.0.0"
486 | }
487 | }
488 | },
489 | "dependencies": {
490 | "@next/env": {
491 | "version": "12.1.0",
492 | "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz",
493 | "integrity": "sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ=="
494 | },
495 | "@next/swc-android-arm64": {
496 | "version": "12.1.0",
497 | "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz",
498 | "integrity": "sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==",
499 | "optional": true
500 | },
501 | "@next/swc-darwin-arm64": {
502 | "version": "12.1.0",
503 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz",
504 | "integrity": "sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==",
505 | "optional": true
506 | },
507 | "@next/swc-darwin-x64": {
508 | "version": "12.1.0",
509 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz",
510 | "integrity": "sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==",
511 | "optional": true
512 | },
513 | "@next/swc-linux-arm-gnueabihf": {
514 | "version": "12.1.0",
515 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz",
516 | "integrity": "sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==",
517 | "optional": true
518 | },
519 | "@next/swc-linux-arm64-gnu": {
520 | "version": "12.1.0",
521 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz",
522 | "integrity": "sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==",
523 | "optional": true
524 | },
525 | "@next/swc-linux-arm64-musl": {
526 | "version": "12.1.0",
527 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz",
528 | "integrity": "sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==",
529 | "optional": true
530 | },
531 | "@next/swc-linux-x64-gnu": {
532 | "version": "12.1.0",
533 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz",
534 | "integrity": "sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==",
535 | "optional": true
536 | },
537 | "@next/swc-linux-x64-musl": {
538 | "version": "12.1.0",
539 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz",
540 | "integrity": "sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==",
541 | "optional": true
542 | },
543 | "@next/swc-win32-arm64-msvc": {
544 | "version": "12.1.0",
545 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz",
546 | "integrity": "sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==",
547 | "optional": true
548 | },
549 | "@next/swc-win32-ia32-msvc": {
550 | "version": "12.1.0",
551 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz",
552 | "integrity": "sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==",
553 | "optional": true
554 | },
555 | "@next/swc-win32-x64-msvc": {
556 | "version": "12.1.0",
557 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz",
558 | "integrity": "sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==",
559 | "optional": true
560 | },
561 | "@yllet/client": {
562 | "version": "3.0.1",
563 | "resolved": "https://registry.npmjs.org/@yllet/client/-/client-3.0.1.tgz",
564 | "integrity": "sha512-ktS3gUIh/CPbbkhvrIxQ40Ws2YdBNiOZKcLOJKdsZnnfEWNus9CUUMUV/8Ev4a1TI1N6WVnvwgMNciiuwdWR1Q==",
565 | "requires": {
566 | "@yllet/support": "^3.0.1",
567 | "isomorphic-form-data": "^2.0.0"
568 | }
569 | },
570 | "@yllet/react": {
571 | "version": "3.0.1",
572 | "resolved": "https://registry.npmjs.org/@yllet/react/-/react-3.0.1.tgz",
573 | "integrity": "sha512-cKlR21US/uR1HOlsZRJBBmk8dcMiufPIcL4Oukm0PLNHEgDL04C75kbzW8DRQlme4vH1mcI1WUPNb8ulBafAhA==",
574 | "requires": {
575 | "@yllet/client": "^3.0.1",
576 | "invariant": "^2.2.4",
577 | "prop-types": "^15.7.2"
578 | }
579 | },
580 | "@yllet/support": {
581 | "version": "3.0.1",
582 | "resolved": "https://registry.npmjs.org/@yllet/support/-/support-3.0.1.tgz",
583 | "integrity": "sha512-NGbwwlgt8CK0RiR+rzj9ak3ikUaL4M7k9ebnEHbjlLPRfiufBy/1tUA3obaUYms3p/SI8J0it0HEUn7UXQmMzg=="
584 | },
585 | "asynckit": {
586 | "version": "0.4.0",
587 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
588 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
589 | },
590 | "caniuse-lite": {
591 | "version": "1.0.30001303",
592 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz",
593 | "integrity": "sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ=="
594 | },
595 | "combined-stream": {
596 | "version": "1.0.8",
597 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
598 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
599 | "requires": {
600 | "delayed-stream": "~1.0.0"
601 | }
602 | },
603 | "delayed-stream": {
604 | "version": "1.0.0",
605 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
606 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
607 | },
608 | "form-data": {
609 | "version": "2.5.1",
610 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
611 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
612 | "requires": {
613 | "asynckit": "^0.4.0",
614 | "combined-stream": "^1.0.6",
615 | "mime-types": "^2.1.12"
616 | }
617 | },
618 | "invariant": {
619 | "version": "2.2.4",
620 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
621 | "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
622 | "requires": {
623 | "loose-envify": "^1.0.0"
624 | }
625 | },
626 | "isomorphic-form-data": {
627 | "version": "2.0.0",
628 | "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-2.0.0.tgz",
629 | "integrity": "sha512-TYgVnXWeESVmQSg4GLVbalmQ+B4NPi/H4eWxqALKj63KsUrcu301YDjBqaOw3h+cbak7Na4Xyps3BiptHtxTfg==",
630 | "requires": {
631 | "form-data": "^2.3.2"
632 | }
633 | },
634 | "js-tokens": {
635 | "version": "4.0.0",
636 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
637 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
638 | },
639 | "loose-envify": {
640 | "version": "1.4.0",
641 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
642 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
643 | "requires": {
644 | "js-tokens": "^3.0.0 || ^4.0.0"
645 | }
646 | },
647 | "mime-db": {
648 | "version": "1.51.0",
649 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
650 | "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
651 | },
652 | "mime-types": {
653 | "version": "2.1.34",
654 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
655 | "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
656 | "requires": {
657 | "mime-db": "1.51.0"
658 | }
659 | },
660 | "nanoid": {
661 | "version": "3.2.0",
662 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
663 | "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA=="
664 | },
665 | "next": {
666 | "version": "12.1.0",
667 | "resolved": "https://registry.npmjs.org/next/-/next-12.1.0.tgz",
668 | "integrity": "sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==",
669 | "requires": {
670 | "@next/env": "12.1.0",
671 | "@next/swc-android-arm64": "12.1.0",
672 | "@next/swc-darwin-arm64": "12.1.0",
673 | "@next/swc-darwin-x64": "12.1.0",
674 | "@next/swc-linux-arm-gnueabihf": "12.1.0",
675 | "@next/swc-linux-arm64-gnu": "12.1.0",
676 | "@next/swc-linux-arm64-musl": "12.1.0",
677 | "@next/swc-linux-x64-gnu": "12.1.0",
678 | "@next/swc-linux-x64-musl": "12.1.0",
679 | "@next/swc-win32-arm64-msvc": "12.1.0",
680 | "@next/swc-win32-ia32-msvc": "12.1.0",
681 | "@next/swc-win32-x64-msvc": "12.1.0",
682 | "caniuse-lite": "^1.0.30001283",
683 | "postcss": "8.4.5",
684 | "styled-jsx": "5.0.0",
685 | "use-subscription": "1.5.1"
686 | }
687 | },
688 | "object-assign": {
689 | "version": "4.1.1",
690 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
691 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
692 | },
693 | "picocolors": {
694 | "version": "1.0.0",
695 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
696 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
697 | },
698 | "postcss": {
699 | "version": "8.4.5",
700 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz",
701 | "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==",
702 | "requires": {
703 | "nanoid": "^3.1.30",
704 | "picocolors": "^1.0.0",
705 | "source-map-js": "^1.0.1"
706 | }
707 | },
708 | "prop-types": {
709 | "version": "15.7.2",
710 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
711 | "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
712 | "requires": {
713 | "loose-envify": "^1.4.0",
714 | "object-assign": "^4.1.1",
715 | "react-is": "^16.8.1"
716 | }
717 | },
718 | "react": {
719 | "version": "17.0.2",
720 | "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
721 | "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
722 | "requires": {
723 | "loose-envify": "^1.1.0",
724 | "object-assign": "^4.1.1"
725 | }
726 | },
727 | "react-dom": {
728 | "version": "17.0.2",
729 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
730 | "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
731 | "requires": {
732 | "loose-envify": "^1.1.0",
733 | "object-assign": "^4.1.1",
734 | "scheduler": "^0.20.2"
735 | }
736 | },
737 | "react-is": {
738 | "version": "16.8.6",
739 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
740 | "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
741 | },
742 | "scheduler": {
743 | "version": "0.20.2",
744 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
745 | "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
746 | "requires": {
747 | "loose-envify": "^1.1.0",
748 | "object-assign": "^4.1.1"
749 | }
750 | },
751 | "source-map-js": {
752 | "version": "1.0.2",
753 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
754 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
755 | },
756 | "styled-jsx": {
757 | "version": "5.0.0",
758 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.0.tgz",
759 | "integrity": "sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA==",
760 | "requires": {}
761 | },
762 | "use-subscription": {
763 | "version": "1.5.1",
764 | "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz",
765 | "integrity": "sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==",
766 | "requires": {
767 | "object-assign": "^4.1.1"
768 | }
769 | }
770 | }
771 | }
772 |
--------------------------------------------------------------------------------