Compare commits

..

49 Commits

Author SHA1 Message Date
Szilárd Dóró
958dec5dfe Merge pull request #2060 from nhost/changeset-release/main
chore: update versions
2023-06-25 13:50:55 +02:00
github-actions[bot]
61e3497a13 chore: update versions 2023-06-24 17:12:27 +00:00
Szilárd Dóró
a7b4e5606d Merge pull request #2069 from nhost/fix/security-keys
fix(webauthn): don't break webauthn form on save
2023-06-24 19:11:12 +02:00
Szilárd Dóró
34d77c9db1 fix(webauthn): don't break webauthn form on save 2023-06-24 18:54:06 +02:00
Szilárd Dóró
4f1efd28a6 Merge pull request #2058 from nhost/renovate/graphql-16.x
chore(deps): update dependency graphql to v16.7.1
2023-06-23 16:00:02 +02:00
Szilárd Dóró
07a45fde0e chore: add changeset 2023-06-23 14:30:07 +02:00
renovate[bot]
9d0380eef3 chore(deps): update dependency graphql to v16.7.1 2023-06-23 12:12:53 +00:00
Szilárd Dóró
ce3ec36b0a Merge pull request #2059 from nhost/fix/404
fix(dashboard): don't redirect to 404 page
2023-06-23 14:10:21 +02:00
Szilárd Dóró
b62a9d19b5 chore(dashboard): improve verbosity of variables 2023-06-23 13:02:32 +02:00
Szilárd Dóró
c1472079c5 Merge pull request #2057 from nhost/renovate/turbo-monorepo
chore(deps): update dependency turbo to v1.10.5
2023-06-23 12:23:29 +02:00
Szilárd Dóró
dd36971798 chore(pnpm): revert pnpm-lock file 2023-06-23 12:17:08 +02:00
Szilárd Dóró
6199c1c555 fix(dashboard): don't redirect to 404 page 2023-06-23 12:11:22 +02:00
Szilárd Dóró
f41fdc12af chore: bump turbo in the Dockerfile, add changeset 2023-06-23 10:23:43 +02:00
renovate[bot]
fc419ffa4d chore(deps): update dependency turbo to v1.10.5 2023-06-22 19:20:02 +00:00
Szilárd Dóró
b7c102e876 Merge pull request #2056 from nhost/changeset-release/main
chore: update versions
2023-06-21 16:01:32 +02:00
github-actions[bot]
873fc36e61 chore: update versions 2023-06-21 13:29:42 +00:00
Szilárd Dóró
29743f0b71 Merge pull request #2053 from nhost/renovate/react-monorepo
chore(deps): update react monorepo and `@storybook/testing-library`
2023-06-21 15:28:22 +02:00
Szilárd Dóró
d904ca2bbf Merge branch 'renovate/react-monorepo' of https://github.com/nhost/nhost into renovate/react-monorepo 2023-06-21 10:29:52 +02:00
Szilárd Dóró
80b22724de chore(deps): bump @storybook/testing-library 2023-06-21 10:29:38 +02:00
renovate[bot]
80e49f4459 chore(deps): update react monorepo 2023-06-21 07:58:56 +00:00
David Barroso
b3d5ead508 chore(docs): fix stripe reference to env vars (#2054) 2023-06-21 09:55:45 +02:00
renovate[bot]
77dcb8c964 chore(deps): update react monorepo 2023-06-19 16:30:54 +00:00
Szilárd Dóró
3488da9dfd Merge pull request #2052 from nhost/changeset-release/main
chore: update versions
2023-06-19 10:13:57 +02:00
github-actions[bot]
0e68a1fdfd chore: update versions 2023-06-16 12:39:47 +00:00
Szilárd Dóró
8797b2bd17 Merge pull request #2051 from nhost/renovate/commander-11.x
fix(deps): update dependency commander to v11
2023-06-16 14:38:37 +02:00
Szilárd Dóró
5ef0b31573 chore: add changeset 2023-06-16 11:20:58 +02:00
renovate[bot]
86e5e0fb50 fix(deps): update dependency commander to v11 2023-06-16 01:45:29 +00:00
Szilárd Dóró
c2d589dd29 Merge pull request #2049 from nhost/changeset-release/main
chore: update versions
2023-06-15 11:34:48 +02:00
github-actions[bot]
4b807d8134 chore: update versions 2023-06-15 09:16:08 +00:00
Szilárd Dóró
ccdabb707f Merge pull request #2048 from nhost/fix/system-env-var-copy
chore(docs): update environment variable docs
2023-06-15 11:14:40 +02:00
Szilárd Dóró
364bc87fd3 docs: update custom env vars section 2023-06-15 10:48:43 +02:00
Szilárd Dóró
cc02902cbb chore: docs: update env var docs 2023-06-15 10:42:00 +02:00
Szilárd Dóró
0e838b9406 Merge pull request #2043 from nhost/changeset-release/main
chore: update versions
2023-06-15 09:47:18 +02:00
Szilárd Dóró
37ebf7d8e2 Merge pull request #2044 from nhost/chore/update-developers-guide
chore: update DEVELOPERS.md
2023-06-15 09:37:53 +02:00
github-actions[bot]
e23af24bdd chore: update versions 2023-06-15 07:29:50 +00:00
Szilárd Dóró
90eb53cf19 Merge pull request #2045 from nhost/fix/storybook-and-tests
fix(dashboard): don't break storybook and don't show warnings during tests
2023-06-15 09:28:21 +02:00
Szilárd Dóró
7e516d7630 Merge pull request #2046 from nhost/fix/functions-and-graphql-header
fix(nhost-js): pass access token to underlying clients
2023-06-15 08:39:01 +02:00
Szilárd Dóró
0861e41e70 fix: dashboard: correct typo in the readme 2023-06-15 08:38:41 +02:00
Szilárd Dóró
057e7e2572 chore: dashboard: update README 2023-06-14 21:30:43 +02:00
Szilárd Dóró
5a4e237a29 fix(nhost-js): pass access token to underlying clients 2023-06-14 21:17:46 +02:00
Szilárd Dóró
c7501c70ae fix: pin playwright to 1.31.0 2023-06-14 18:57:27 +02:00
Szilárd Dóró
6a45c1abad fix: dashboard: don't break storybook 2023-06-14 15:29:53 +02:00
Szilárd Dóró
660d339e14 fix: dashboard: prevent warnings during tests 2023-06-14 15:29:37 +02:00
Szilárd Dóró
3dca08595d Merge pull request #2038 from nhost/fix/token-reload
fix(hasura-auth-js): prevent infinite token refresh
2023-06-14 14:38:22 +02:00
Szilárd Dóró
7c501c4e4f chore: add section about selecting versions 2023-06-14 14:36:17 +02:00
Szilárd Dóró
5e1d5b737c chore: extend DEVELOPERS.md with changeset info 2023-06-14 14:27:08 +02:00
Szilárd Dóró
1d04ad6306 fix: hasura-auth-js: don't break unit tests 2023-06-14 12:01:13 +02:00
Szilárd Dóró
a4fa5f6f59 fix: don't break unit tests 2023-06-14 10:06:31 +02:00
Szilárd Dóró
7e973d568a fix: hasura-auth-js: prevent infinite token refresh 2023-06-14 09:46:58 +02:00
73 changed files with 1380 additions and 1044 deletions

View File

@@ -1,16 +1,37 @@
# Developer guide
# Developer Guide
## Requirements
- This repository works with **Node 16**
### Node.js v18
- We use [pnpm](https://pnpm.io/) as a package manager to speed up development and builds, and as a basis for our monorepo. You need to make sure it's installed on your machine. There are [several ways to install it](https://pnpm.io/installation), but the easiest way is with `npm`:
_⚠️ Node.js v16 is also supported for the time being but support will be dropped in the near future_.
### [pnpm](https://pnpm.io/) package manager
The easiest way to install `pnpm` if it's not installed on your machine yet is to use `npm`:
```sh
$ npm install -g pnpm
```
- Our tests and examples use the Nhost CLI, to run the backend services locally. You can follow the installation instructions in [our documentation](https://docs.nhost.io/get-started/cli-workflow/install-cli).
### [Nhost CLI](https://docs.nhost.io/cli)
- The CLI is primarily used for running the E2E tests
- Please refer to the [installation guide](https://docs.nhost.io/get-started/cli-workflow/install-cli) if you have not installed it yet
## File Structure
The repository is organized as a monorepo, with the following structure (only relevant folders are shown):
```
assets/ # Assets used in the README
config/ # Configuration files for the monorepo
dashboard/ # Dashboard
docs/ # Documentation website
examples/ # Example projects
packages/ # Core packages
integrations/ # These are packages that rely on the core packages
```
## Get started
@@ -31,25 +52,25 @@ $ pnpm install
### Development
Although package references are correctly updated on the fly for TypeScript, example projects won't
see the changes because they are depending on the build output. To fix this, you can run packages
in development mode.
Although package references are correctly updated on the fly for TypeScript, example projects and the dashboard won't see the changes because they are depending on the build output. To fix this, you can run packages in development mode.
Running packages in development mode is as simple as:
Running packages in development mode from the root folder is as simple as:
```sh
$ pnpm dev
```
Our packages are linked together using [PNPM's workspace](https://pnpm.io/workspaces) feature. Vite automatically detects changes in the dependencies and rebuilds everything, so that the changes are immediately reflected in the other packages.
Our packages are linked together using [PNPM's workspace](https://pnpm.io/workspaces) feature. Next.js and Vite automatically detect changes in the dependencies and rebuild everything, so the changes will be reflected in the examples and the dashboard.
### Use examples
**Note:** It's possible that Next.js or Vite throw an error when you run `pnpm dev`. Restarting the process should fix it.
### Use Examples
Examples are a great way to test your changes in practice. Make sure you've `pnpm dev` running in your terminal and then run an example.
Let's follow the instructions to run [react-apollo example](https://github.com/nhost/nhost/blob/main/examples/react-apollo/README.md).
## Run the documentation website locally
## Edit Documentation
The easier way to contribute to our documentation is to go to the `docs` folder and follow the [instructions to start local development](https://github.com/nhost/nhost/blob/main/docs/README.md):
@@ -60,9 +81,9 @@ $ pnpm install
$ pnpm start
```
## Run test suites
## Run Test Suites
### Unit tests
### Unit Tests
You can run the unit tests with the following command from the repository root:
@@ -70,7 +91,7 @@ You can run the unit tests with the following command from the repository root:
$ pnpm test
```
### End-to-end tests
### E2E Tests
Each package that defines end-to-end tests embeds their own Nhost configuration, that will be automatically when running the tests. As a result, you must make sure you are not running the Nhost CLI before running the tests.
@@ -83,24 +104,60 @@ $ pnpm e2e
## Changesets
If you've made changes to the packages, you must describe those changes so that they can be reflected in the next release.
We use [changesets](https://github.com/changesets/changesets) to support our versioning and release workflows. When you submit a pull request, a bot checks if some changesets are present, and if not, it directs you to add them.
We use [changesets](https://github.com/changesets/changesets) to support our versioning and release workflows. When you submit a pull request, a bot checks if changesets are present, and if not, it asks you to add them.
The most comprehensive way to add a changeset is to run the following command in the repository root:
To create a changeset, run the following command from the repository root:
```sh
$ pnpm changeset
```
This will create a file in the `.changeset` directory. You can edit it to give more details about the change you just made.
This command will guide you through the process of creating a changeset. It will create a file in the `.changeset` directory.
You can take a look at the changeset documentation: [How to add a changeset](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).
## Committing changes
### Selecting the Version
You'll notice that `git commit` takes a few seconds to run. We set a commit hook that scans the changes in the code, automatically generates documentation from the inline [TSDoc](https://tsdoc.org/) annotations, and adds these generated documentation files to the commit. They automatically update the [reference documentation](https://docs.nhost.io/reference).
When you create a changeset, you will be asked to select the version of the package that you are bumping. The versioning scheme is as follows:
- **major**
- For breaking changes (e.g: changing the function signature, etc.)
- Should be avoided as much as possible as it will require users to update their code. Instead, consider supporting both the old and the new API simultaneously for a while.
- For example: `v1.5.8` -> `v2.0.0`
- **minor**
- For new features (e.g: adding a new page to the dashboard, etc.)
- For example: `v1.5.8` -> `v1.6.0`
- **patch**
- For bug fixes (e.g: fixing a typo, etc.)
- For example: `v1.5.8` -> `v1.5.9`
<!-- ## Good practices
- lint
- prettier
- documentation -->
### Writing Good Changesets
A concise summary that describes the changes should be added to each PR. This summary will be used as the changeset description.
The following structure is used for describing changes:
- **The type of the change**:
- fix
- feat
- chore
- docs
- **The scope of the change** (_broader scopes (e.g: dashboard, hasura-storage-js, etc.) are not recommended as GitHub Releases already contain which project is being bumped_):
- projects
- deployments
- deps
- etc.
- **A short summary of the changes that were made**
**Examples:**
- `fix(deployments): use correct timestamp for deployment details`
- `chore(deps): bump @types/react to v18.2.8`
- `feat(secrets): enable secrets`
- etc.
You can always take a look at examples of changesets in the [GitHub Releases section](https://github.com/nhost/nhost/releases).

View File

@@ -2,13 +2,14 @@ import '@fontsource/inter';
import '@fontsource/inter/500.css';
import '@fontsource/inter/700.css';
import { CssBaseline, ThemeProvider } from '@mui/material';
import { NhostClient, NhostProvider } from '@nhost/nextjs';
import { NhostApolloProvider } from '@nhost/react-apollo';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Buffer } from 'buffer';
import { initialize, mswDecorator } from 'msw-storybook-addon';
import { RouterContext } from 'next/dist/shared/lib/router-context';
import { createTheme } from '../src/components/ui/v2/createTheme';
import '../src/styles/globals.css';
import createTheme from '../src/theme/createTheme';
global.Buffer = Buffer;
@@ -56,5 +57,10 @@ export const decorators = [
<Story />
</NhostApolloProvider>
),
(Story) => (
<NhostProvider nhost={new NhostClient({ subdomain: 'local' })}>
<Story />
</NhostProvider>
),
mswDecorator,
];

View File

@@ -1,5 +1,36 @@
# @nhost/dashboard
## 0.17.15
### Patch Changes
- f41fdc12a: chore(deps): bump `turbo` to `1.10.5`
- 6199c1c55: fix(projects): don't redirect to 404 page
- Updated dependencies [07a45fde0]
- @nhost/react-apollo@5.0.28
- @nhost/nextjs@1.13.30
## 0.17.14
### Patch Changes
- 80b22724d: chore(deps): bump `@types/react` to `v18.2.13`, `@types/react-dom` to `v18.2.6` and `@storybook/testing-library` to `v0.2.0`
## 0.17.13
### Patch Changes
- cc02902cb: chore(docs): update environment variable documentation
## 0.17.12
### Patch Changes
- 660d339e1: fix(storybook): don't break storybook
- 660d339e1: fix(tests): prevent warnings during tests
- @nhost/react-apollo@5.0.27
- @nhost/nextjs@1.13.29
## 0.17.11
### Patch Changes

View File

@@ -3,7 +3,7 @@ RUN apk add --no-cache libc6-compat
RUN apk update
WORKDIR /app
RUN yarn global add turbo@1.10.3
RUN yarn global add turbo@1.10.5
COPY . .
RUN turbo prune --scope="@nhost/dashboard" --docker

View File

@@ -3,10 +3,20 @@
This is the Nhost Dashboard, a web application that allows you to manage your Nhost projects.
To get started, you need to have an Nhost project. If you don't have one, you can [create a project here](https://app.nhost.io).
First, install the dependencies:
```bash
pnpm install
```
Then, run the development server:
```bash
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
## Environment
### Setup Environment Variables
@@ -54,6 +64,12 @@ Components are documented using [Storybook](https://storybook.js.org/). To run S
pnpm storybook
```
By default, Storybook will run on port `6006`. You can change this by passing the `--port` flag:
```bash
pnpm storybook --port 6007
```
### General Environment Variables
| Name | Description |
@@ -110,15 +126,19 @@ pnpm storybook
| `@typescript-eslint/naming-convention` | Enforces a consistent naming convention. |
| `no-restricted-imports` | Enforces absolute imports and consistent import paths for components from `src/components/ui` folder. |
### End-to-End Tests
### Unit Tests
End-to-end tests are written using [Playwright](https://playwright.dev/). To run the tests, run the following command:
Unit tests are written using [Vitest](https://vitest.dev/). To run the tests, run the following command:
```bash
pnpm e2e
pnpm test
```
Most of the tests require access to the Nhost test user. To run these tests, you need to set the following environment variables in `.env.test`:
### End-to-End Tests
Most of the end-to-end tests require access to an Nhost test user and a live project. You can register a user and create a test project on the [Nhost Dashboard](https://app.nhost.io/).
Next, you need to create a project. Create a `.env.test` file with the following variables:
```
NHOST_TEST_DASHBOARD_URL=<test_dashboard_url>
@@ -128,3 +148,20 @@ NHOST_TEST_WORKSPACE_NAME=<test_workspace_name>
NHOST_TEST_PROJECT_NAME=<test_project_name>
NHOST_TEST_PROJECT_ADMIN_SECRET=<test_project_admin_secret>
```
**Required Variables**:
- `NHOST_TEST_DASHBOARD_URL`: The URL to run the tests against (e.g: http://localhost:3000 or https://staging.app.nhost.io)
- `NHOST_TEST_USER_EMAIL`: Email address of the test user that owns the test project
- `NHOST_TEST_USER_PASSWORD`: Password of the test user that owns the test project
- `NHOST_TEST_WORKSPACE_NAME`: Name of the workspace that contains the test project
- `NHOST_TEST_PROJECT_NAME`: Name of the test project
- `NHOST_TEST_PROJECT_ADMIN_SECRET`: Admin secret of the test project
Make sure to copy the workspace and project information from the [Nhost Dashboard](https://app.nhost.io/).
End-to-end tests are written using [Playwright](https://playwright.dev/). To run the tests, run the following command:
```bash
pnpm e2e
```

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/dashboard",
"version": "0.17.11",
"version": "0.17.15",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
@@ -11,11 +11,11 @@
"lint": "next lint --max-warnings 0",
"test": "vitest",
"codegen": "graphql-codegen --config graphql.config.yaml --errors-only",
"nhost:dev": "nhost up",
"format": "prettier --write \"src/**/*.{js,ts,tsx,jsx,json,md}\" --plugin-search-dir=.",
"storybook": "start-storybook -p 6006 -s public",
"build-storybook": "build-storybook",
"e2e": "npx playwright@1.34.0 install --with-deps && playwright test"
"install-browsers": "pnpm dlx playwright@1.31.0 install --with-deps",
"e2e": "pnpm install-browsers && pnpm dlx playwright@1.31.0 test"
},
"dependencies": {
"@apollo/client": "^3.7.10",
@@ -87,7 +87,7 @@
"@graphql-codegen/typescript-operations": "^3.0.0",
"@graphql-codegen/typescript-react-apollo": "^3.3.1",
"@next/bundle-analyzer": "^12.3.1",
"@playwright/test": "^1.34.0",
"@playwright/test": "1.31.0",
"@storybook/addon-actions": "^6.5.14",
"@storybook/addon-essentials": "^6.5.14",
"@storybook/addon-interactions": "^6.5.14",
@@ -96,7 +96,7 @@
"@storybook/builder-webpack5": "^6.5.14",
"@storybook/manager-webpack5": "^6.5.14",
"@storybook/react": "^6.5.14",
"@storybook/testing-library": "^0.0.13",
"@storybook/testing-library": "^0.2.0",
"@testing-library/dom": "^9.0.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",

View File

@@ -66,7 +66,10 @@ export default function WebAuthnSettings() {
config: {
auth: {
method: {
webauthn: values,
webauthn: {...values,
relyingParty: {
name: currentProject.name,
}},
},
},
},

View File

@@ -3,6 +3,7 @@ import { Button } from '@/components/ui/v2/Button';
import { Text } from '@/components/ui/v2/Text';
import hasuraMetadataQuery from '@/tests/msw/mocks/rest/hasuraMetadataQuery';
import tableQuery from '@/tests/msw/mocks/rest/tableQuery';
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
@@ -34,7 +35,7 @@ const defaultParameters = {
},
},
msw: {
handlers: [tableQuery, hasuraMetadataQuery],
handlers: [tokenQuery, tableQuery, hasuraMetadataQuery],
},
};

View File

@@ -187,11 +187,11 @@ export default async function fetchTable({
const queryError = responseData as QueryError;
const schemaNotFound =
POSTGRESQL_ERROR_CODES.SCHEMA_NOT_FOUND ===
queryError.internal.error.status_code;
queryError.internal?.error?.status_code;
const tableNotFound =
POSTGRESQL_ERROR_CODES.TABLE_NOT_FOUND ===
queryError.internal.error.status_code;
queryError.internal?.error?.status_code;
if (schemaNotFound || tableNotFound) {
return {
@@ -203,7 +203,7 @@ export default async function fetchTable({
}
if (
queryError.internal.error.status_code ===
queryError.internal?.error?.status_code ===
POSTGRESQL_ERROR_CODES.COLUMNS_NOT_FOUND
) {
return {
@@ -214,7 +214,7 @@ export default async function fetchTable({
};
}
throw new Error(queryError.internal.error.message);
throw new Error(queryError.internal?.error?.message);
}
if ('error' in responseData) {

View File

@@ -1,3 +1,4 @@
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import { render, screen, waitFor } from '@/tests/testUtils';
import { graphql } from 'msw';
import { setupServer } from 'msw/node';
@@ -5,6 +6,7 @@ import { beforeAll, expect, test } from 'vitest';
import HasuraCorsDomainSettings from './HasuraCorsDomainSettings';
const server = setupServer(
tokenQuery,
graphql.query('GetHasuraSettings', (_req, res, ctx) =>
res(
ctx.data({
@@ -15,7 +17,14 @@ const server = setupServer(
version: 'v2.25.1-ce',
settings: {
corsDomain: ['*'],
enableAllowList: false,
enableRemoteSchemaPermissions: false,
enableConsole: false,
devMode: false,
enabledAPIs: [],
},
logs: [],
events: [],
},
},
}),
@@ -56,7 +65,14 @@ test('should enable switch by default when CORS domain is set to one or more dom
version: 'v2.25.1-ce',
settings: {
corsDomain: ['https://example.com', 'https://*.example.com'],
enableAllowList: false,
enableRemoteSchemaPermissions: false,
enableConsole: false,
devMode: false,
enabledAPIs: [],
},
logs: [],
events: [],
},
},
}),

View File

@@ -3,7 +3,7 @@ import type { Project, Workspace } from '@/types/application';
import { ApplicationStatus } from '@/types/application';
import { getHasuraAdminSecret } from '@/utils/env';
import { GetWorkspaceAndProjectDocument } from '@/utils/__generated__/graphql';
import { useNhostClient, useUserData } from '@nhost/nextjs';
import { useAuthenticationStatus, useNhostClient } from '@nhost/nextjs';
import type { RefetchOptions } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/router';
@@ -34,14 +34,24 @@ export interface UseCurrentWorkspaceAndProjectReturnType {
export default function useCurrentWorkspaceAndProject(): UseCurrentWorkspaceAndProjectReturnType {
const client = useNhostClient();
const user = useUserData();
const isPlatform = useIsPlatform();
const { isAuthenticated, isLoading: isAuthLoading } =
useAuthenticationStatus();
const {
query: { workspaceSlug, appSlug },
isReady,
isReady: isRouterReady,
} = useRouter();
const isWorkspaceSlugAvailable = Boolean(workspaceSlug);
const shouldFetchWorkspaceAndProject =
isPlatform &&
isRouterReady &&
isWorkspaceSlugAvailable &&
isAuthenticated &&
!isAuthLoading;
// We can't use the hook exported by the codegen here because there are cases
// where it doesn't target the Nhost backend, but the currently active project
// instead.
@@ -59,7 +69,7 @@ export default function useCurrentWorkspaceAndProject(): UseCurrentWorkspaceAndP
}),
{
keepPreviousData: true,
enabled: isPlatform && isReady && !!workspaceSlug && !!user,
enabled: shouldFetchWorkspaceAndProject,
// multiple components are relying on this query, so we don't want to
// refetch it too often - kind of a hack, should be improved later
staleTime: 1000,
@@ -142,7 +152,7 @@ export default function useCurrentWorkspaceAndProject(): UseCurrentWorkspaceAndP
return {
currentWorkspace,
currentProject,
loading: response ? false : isFetching,
loading: response ? false : isFetching || isAuthLoading,
error: response?.error
? new Error(error?.message || 'Unknown error occurred.')
: null,

View File

@@ -1,4 +1,3 @@
import type { ProjectFragment } from '@/utils/__generated__/graphql';
import {
getAuthServiceUrl,
getDatabaseServiceUrl,
@@ -8,6 +7,7 @@ import {
getStorageServiceUrl,
isPlatform,
} from '@/utils/env';
import type { ProjectFragment } from '@/utils/__generated__/graphql';
export type NhostService =
| 'auth'

View File

@@ -123,7 +123,7 @@ export default function SystemEnvironmentVariableSettings() {
return (
<SettingsContainer
title="System Environment Variables"
description="Environment Variables are key-value pairs configured outside your source code. They are used to store environment-specific values such as API keys."
description="System environment variables are automatically generated from the configuration file and your project's subdomain and region."
docsLink="https://docs.nhost.io/platform/environment-variables#system-environment-variables"
rootClassName="gap-0"
className="mt-2 mb-2.5 px-0"

View File

@@ -1,4 +1,5 @@
import { mockApplication, mockWorkspace } from '@/tests/mocks';
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import { queryClient, render, screen } from '@/tests/testUtils';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
@@ -34,6 +35,7 @@ vi.mock('next/router', () => ({
}));
const server = setupServer(
tokenQuery,
rest.get('https://local.graphql.nhost.run/v1', (_req, res, ctx) =>
res(ctx.status(200)),
),
@@ -135,6 +137,7 @@ test('should render an empty state when GitHub is connected, but there are no de
test('should render a list of deployments', async () => {
server.use(
tokenQuery,
rest.post('https://local.graphql.nhost.run/v1', async (_req, res, ctx) => {
const { operationName } = await _req.json();
@@ -194,6 +197,7 @@ test('should render a list of deployments', async () => {
test('should disable redeployments if a deployment is already in progress', async () => {
server.use(
tokenQuery,
rest.post('https://local.graphql.nhost.run/v1', async (req, res, ctx) => {
const { operationName } = await req.json();

View File

@@ -9,6 +9,7 @@ import {
resourcesUpdatedQuery,
} from '@/tests/msw/mocks/graphql/resourceSettingsQuery';
import updateConfigMutation from '@/tests/msw/mocks/graphql/updateConfigMutation';
import tokenQuery from '@/tests/msw/mocks/rest/tokenQuery';
import {
fireEvent,
render,
@@ -35,6 +36,7 @@ vi.mock('next/router', () => ({
}));
const server = setupServer(
tokenQuery,
resourcesAvailableQuery,
getProPlanOnlyQuery,
getWorkspaceAndProjectQuery,

View File

@@ -88,6 +88,7 @@ export const mockWorkspace: Workspace = {
slug: 'test-workspace',
workspaceMembers: [],
projects: [mockApplication],
creatorUserId: '1',
};
export const mockSession: NhostSession = {

View File

@@ -1,7 +1,7 @@
import { rest } from 'msw';
const hasuraMetadataQuery = rest.post(
'http://localhost:8080/v1/metadata',
'https://local.hasura.nhost.run/v1/metadata',
(_req, res, ctx) =>
res(
ctx.delay(250),

View File

@@ -1,7 +1,7 @@
import { rest } from 'msw';
const tableQuery = rest.post(
'http://localhost:8080/v2/query',
'https://local.hasura.nhost.run/v2/query',
async (req, res, ctx) => {
const body = await req.json();

View File

@@ -0,0 +1,32 @@
import { faker } from '@faker-js/faker';
import type { NhostSession } from '@nhost/nextjs';
import { rest } from 'msw';
const tokenQuery = rest.post(
`https://local.auth.nhost.run/v1/token`,
(_req, res, ctx) =>
res(
ctx.json<NhostSession>({
accessToken: faker.datatype.string(40),
refreshToken: faker.datatype.uuid(),
accessTokenExpiresIn: 900,
user: {
id: faker.datatype.uuid(),
createdAt: faker.date.past().toUTCString(),
displayName: `${faker.name.firstName()} ${faker.name.lastName()}`,
avatarUrl: faker.internet.avatar(),
locale: 'en',
isAnonymous: false,
emailVerified: true,
defaultRole: 'user',
roles: ['user', 'me'],
phoneNumber: null,
phoneNumberVerified: false,
activeMfaType: null,
metadata: {},
},
}),
),
);
export default tokenQuery;

View File

@@ -32,13 +32,13 @@ process.env = {
NODE_ENV: 'development',
NEXT_PUBLIC_NHOST_PLATFORM: 'false',
NEXT_PUBLIC_ENV: 'dev',
NEXT_PUBLIC_NHOST_AUTH_URL: 'https://localdev.nhost.run/v1/auth',
NEXT_PUBLIC_NHOST_FUNCTIONS_URL: 'https://localdev.nhost.run/v1/functions',
NEXT_PUBLIC_NHOST_GRAPHQL_URL: 'https://localdev.nhost.run/v1/graphql',
NEXT_PUBLIC_NHOST_STORAGE_URL: 'https://localdev.nhost.run/v1/storage',
NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL: 'http://localhost:9695',
NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL: 'http://localhost:9693',
NEXT_PUBLIC_NHOST_HASURA_API_URL: 'http://localhost:8080',
NEXT_PUBLIC_NHOST_AUTH_URL: 'https://local.auth.nhost.run/v1',
NEXT_PUBLIC_NHOST_FUNCTIONS_URL: 'https://local.functions.nhost.run/v1',
NEXT_PUBLIC_NHOST_GRAPHQL_URL: 'https://local.graphql.nhost.run/v1',
NEXT_PUBLIC_NHOST_STORAGE_URL: 'https://local.storage.nhost.run/v1',
NEXT_PUBLIC_NHOST_HASURA_CONSOLE_URL: 'https://local.hasura.nhost.run',
NEXT_PUBLIC_NHOST_HASURA_MIGRATIONS_API_URL: 'https://local.hasura.nhost.run',
NEXT_PUBLIC_NHOST_HASURA_API_URL: 'https://local.hasura.nhost.run',
};
export const queryClient = new QueryClient({

View File

@@ -33,5 +33,5 @@
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules", ".nhost", "nhost", "functions"]
"exclude": ["node_modules", ".nhost", "nhost", "functions", "playwright.config.ts"]
}

View File

@@ -1,5 +1,11 @@
# @nhost/docs
## 0.3.3
### Patch Changes
- cc02902cb: chore(docs): update environment variable documentation
## 0.3.2
### Patch Changes

View File

@@ -138,13 +138,21 @@ export default server
Add `STRIPE_SECRET_KEY` as an environment variable.
If you're using Nhost, add `STRIPE_SECRET_KEY` to `.env.development` like this:
If you're using Nhost, add `STRIPE_SECRET_KEY` to `nhost.toml` like this:
```
[[ global.environment ]]
name=STRIPE_SECRET_KEY
value='{{ secrets.STRIPE_SECRET_KEY }}'
```
And then add to your `.secrets` file:
```
STRIPE_SECRET_KEY=sk_test_***
```
And add the production key (`sk_live_***`) to [environment variables](/platform/environment-variables) in the Nhost dashboard.
In production set your secret with your stripe production key (`sk_live_***`) in the Nhost dashboard.
Learn more about [Stripe API keys](https://stripe.com/docs/keys#obtain-api-keys).

View File

@@ -6,10 +6,6 @@ image: /img/og/platform/environment-variables.png
Environment Variables are key-value pairs configured outside your source code. They are used to store environment-specific values such as API keys.
You can manage your project's Environment Variables in Nhost Dashboard under **Variables**. When you define a new variable, you can set one value for **production** and one for **development**.
![Environment Variables](/img/platform/environment-variables/environment-variables.png)
Environment Variables are available for:
- [Hasura GraphQL Engine](/graphql)
@@ -17,13 +13,44 @@ Environment Variables are available for:
When an Environment Variable has updated the changes happen immediately for Hasura GraphQL Engine. For Serverless Functions, a new deployment via [Git](/platform/git) is required.
## Custom Environment Variables
You can manage your project's Environment Variables in the Nhost Dashboard or by using the configuration file.
### Dashboard
![Environment Variables](/img/platform/environment-variables/environment-variables.png)
Environment Variables can be managed in the Nhost Dashboard under **Settings** &rarr; **Environment Variables**.
### Configuration File
Environment Variables can also be managed by adding new `[[global.environment]]` sections to the `nhost.toml` file.
```toml
[global]
[[global.environment]]
name = 'MY_ENV_VAR'
value = '<first-value>'
[[global.environment]]
name = 'MY_OTHER_ENV_VAR'
value = '<second-value>'
# ... omitted for brevity
```
These environment variables will also be available on the Nhost Dashboard after committing and pushing the changes to your Git repository.
## System Environment Variables
System Environment Variables are automatically available in production and during local development. The following system Environment Variables are available:
System environment variables are automatically generated from the configuration file and your project's subdomain and region.
The following system environment variables are available:
- `NHOST_ADMIN_SECRET`
- `NHOST_WEBHOOK_SECRET`
- `NHOST_BACKEND_URL` ([deprecated](https://github.com/nhost/nhost/discussions/1319))
- ~~`NHOST_BACKEND_URL`~~ ([deprecated](https://github.com/nhost/nhost/discussions/1319))
- `NHOST_SUBDOMAIN`
- `NHOST_REGION`
- `NHOST_HASURA_URL`
@@ -33,7 +60,9 @@ System Environment Variables are automatically available in production and durin
- `NHOST_FUNCTIONS_URL`
- `NHOST_JWT_SECRET`
Example values:
`NHOST_ADMIN_SECRET`, `NHOST_WEBHOOK_SECRET` and `NHOST_JWT_SECRET` are populated with values from the configuration file. The rest of the system environment variables are populated with values from your project's subdomain and region.
**Example values**:
```text
NHOST_ADMIN_SECRET=e7w36ag287qn5qry795f6ymm57qgvqup
@@ -58,10 +87,3 @@ NHOST_FUNCTIONS_URL=https://abc123abc.functions.eu-central-1.nhost.run/v1
NHOST_JWT_SECRET={"type": "HS256", "key": "vumpbe2w2mgaqj5yqfp7dvxu6kywtvsgb68ejpdaqxerea8jwrsszdp2dhkjxsh4df69pzm3ja6ukedx8ja43zdt6q9kgbgg2w9vh2sedeppukud9a2qzy29v3afdn7m"}
```
## Development Environment Variables
When developing locally using the [CLI](/cli), Environment Variables set in `.env.development` are available in your local environment. There are two ways to manage them:
1. Edit the `.env.development` file manually.
2. Add development Environment Variables in the Nhost Dashboard and use `nhost env pull` to sync them. This way, your team members will also have access to the same Environment Variables.

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/docs",
"version": "0.3.2",
"version": "0.3.3",
"private": true,
"scripts": {
"docusaurus": "docusaurus",

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -7,8 +7,6 @@ configuration:
custom_name: createdAt
expires_at:
custom_name: expiresAt
refresh_token:
custom_name: refreshToken
refresh_token_hash:
custom_name: refreshTokenHash
type:
@@ -18,7 +16,6 @@ configuration:
custom_column_names:
created_at: createdAt
expires_at: expiresAt
refresh_token: refreshToken
refresh_token_hash: refreshTokenHash
type: type
user_id: userId
@@ -44,6 +41,7 @@ select_permissions:
- role: user
permission:
columns:
- id
- created_at
- expires_at
- metadata

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -22,8 +22,9 @@
"scripts": {
"dev": "vite --host localhost --port 3000",
"generate": "graphql-codegen --config graphql.config.yaml",
"install-browsers": "pnpm dlx playwright@1.31.0 install --with-deps",
"e2e": "pnpm e2e:start-backend && pnpm e2e:test",
"e2e:test": "npx playwright@1.34.0 install --with-deps && playwright test; nhost down",
"e2e:test": "pnpm install-browsers && pnpm dlx playwright@1.31.0 test; nhost down",
"e2e:start-backend": "cp .secrets.example .secrets && nhost up",
"e2e:start-ui": "run-s build preview",
"build": "vite build",
@@ -51,7 +52,7 @@
"@faker-js/faker": "^7.6.0",
"@graphql-codegen/cli": "^2.16.5",
"@nuintun/qrcode": "^3.3.2",
"@playwright/test": "^1.34.0",
"@playwright/test": "1.31.0",
"@types/pngjs": "^6.0.1",
"@types/react": "^18.2.6",
"@types/react-dom": "^18.2.4",

View File

@@ -58,8 +58,8 @@ devDependencies:
specifier: ^3.3.2
version: 3.3.2
'@playwright/test':
specifier: ^1.34.0
version: 1.34.0
specifier: 1.31.0
version: 1.31.0
'@types/pngjs':
specifier: ^6.0.1
version: 6.0.1
@@ -1327,13 +1327,13 @@ packages:
webcrypto-core: 1.7.7
dev: true
/@playwright/test@1.34.0:
resolution: {integrity: sha512-GIALJVODOIrMflLV54H3Cow635OfrTwOu24ZTDyKC66uchtFX2NcCRq83cLdakMjZKYK78lODNLQSYBj2OgaTw==}
/@playwright/test@1.31.0:
resolution: {integrity: sha512-Ys5s/06Dg9g3zAIdCIb/UOBYim3U7Zjb3DvC6XBtnRmnglH5O47iwYzmtxXu9fhSyzI2Jn28apkXIOD81GgCdw==}
engines: {node: '>=14'}
hasBin: true
dependencies:
'@types/node': 20.2.5
playwright-core: 1.34.0
playwright-core: 1.31.0
optionalDependencies:
fsevents: 2.3.2
dev: true
@@ -3039,9 +3039,10 @@ packages:
engines: {node: '>=8.6'}
dev: true
/playwright-core@1.34.0:
resolution: {integrity: sha512-fMUY1+iR6kYbJF/EsOOqzBA99ZHXbw9sYPNjwA4X/oV0hVF/1aGlWYBGPVUEqxBkGANDKMziYoOdKGU5DIP5Gg==}
/playwright-core@1.31.0:
resolution: {integrity: sha512-/KquBjS5DcASCh8cGeNVHuC0kyb7c9plKTwaKxgOGtxT7+DZO2fjmFvPDBSXslEIK5CeOO/2kk5rOCktFXKEdA==}
engines: {node: '>=14'}
hasBin: true
dev: true
/pngjs@7.0.0:

View File

@@ -1,5 +1,20 @@
# @nhost/apollo
## 5.2.12
### Patch Changes
- 07a45fde0: chore(deps): bump `graphql` to `v16.7.1`
- Updated dependencies [07a45fde0]
- @nhost/nhost-js@2.2.10
## 5.2.11
### Patch Changes
- Updated dependencies [5a4e237a2]
- @nhost/nhost-js@2.2.9
## 5.2.10
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/apollo",
"version": "5.2.10",
"version": "5.2.12",
"description": "Nhost Apollo Client library",
"license": "MIT",
"keywords": [
@@ -64,7 +64,7 @@
"@nhost/nhost-js": "workspace:*"
},
"dependencies": {
"graphql": "16.6.0",
"graphql": "16.7.1",
"graphql-ws": "^5.10.1"
},
"devDependencies": {

View File

@@ -1,5 +1,21 @@
# @nhost/react-apollo
## 5.0.28
### Patch Changes
- 07a45fde0: chore(deps): bump `graphql` to `v16.7.1`
- Updated dependencies [07a45fde0]
- @nhost/apollo@5.2.12
- @nhost/react@2.0.24
## 5.0.27
### Patch Changes
- @nhost/apollo@5.2.11
- @nhost/react@2.0.23
## 5.0.26
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/react-apollo",
"version": "5.0.26",
"version": "5.0.28",
"description": "Nhost React Apollo client",
"license": "MIT",
"keywords": [
@@ -74,7 +74,7 @@
"@apollo/client": "^3.7.10",
"@nhost/react": "workspace:*",
"@types/react": "^18.0.34",
"graphql": "16.6.0",
"graphql": "16.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}

View File

@@ -1,5 +1,18 @@
# @nhost/react-urql
## 2.0.25
### Patch Changes
- 07a45fde0: chore(deps): bump `graphql` to `v16.7.1`
- @nhost/react@2.0.24
## 2.0.24
### Patch Changes
- @nhost/react@2.0.23
## 2.0.23
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/react-urql",
"version": "2.0.23",
"version": "2.0.25",
"description": "Nhost React URQL client",
"license": "MIT",
"keywords": [
@@ -73,7 +73,7 @@
"devDependencies": {
"@nhost/react": "workspace:*",
"@types/react": "^18.0.34",
"graphql": "16.6.0",
"graphql": "16.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"urql": "^4.0.0"

View File

@@ -1,5 +1,11 @@
# @nhost/stripe-graphql-js
## 1.0.4
### Patch Changes
- 07a45fde0: chore(deps): bump `graphql` to `v16.7.1`
## 1.0.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/stripe-graphql-js",
"version": "1.0.3",
"version": "1.0.4",
"description": "Stripe GraphQL API",
"license": "MIT",
"keywords": [
@@ -41,7 +41,7 @@
},
"dependencies": {
"@pothos/core": "^3.21.0",
"graphql": "16.6.0",
"graphql": "16.7.1",
"graphql-scalars": "^1.18.0",
"graphql-yoga": "^3.4.0",
"jsonwebtoken": "^9.0.0",

View File

@@ -76,7 +76,7 @@
"husky": "^8.0.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.7.1",
"turbo": "1.10.3",
"turbo": "1.10.5",
"typedoc": "^0.22.18",
"typescript": "4.9.5",
"vite": "^4.3.8",
@@ -85,7 +85,7 @@
"vitest": "^0.32.0"
},
"resolutions": {
"graphql": "16.6.0"
"graphql": "16.7.1"
},
"packageManager": "pnpm@8.6.2",
"engines": {

View File

@@ -1,5 +1,11 @@
# @nhost/docgen
## 0.1.11
### Patch Changes
- 5ef0b3157: chore(deps): bump `commander` to `v11`
## 0.1.10
### Patch Changes

View File

@@ -2,7 +2,7 @@
"name": "@nhost/docgen",
"description": "Documentation generator for classes and functions",
"private": true,
"version": "0.1.10",
"version": "0.1.11",
"license": "MIT",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
@@ -40,7 +40,7 @@
},
"dependencies": {
"chalk": "4",
"commander": "^10.0.0",
"commander": "^11.0.0",
"just-kebab-case": "^4.1.1",
"prettier": "^2.7.1",
"valtio": "^1.6.4"

View File

@@ -1,5 +1,11 @@
# @nhost/graphql-js
## 0.1.4
### Patch Changes
- 07a45fde0: chore(deps): bump `graphql` to `v16.7.1`
## 0.1.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/graphql-js",
"version": "0.1.3",
"version": "0.1.4",
"description": "Nhost GraphQL client",
"license": "MIT",
"keywords": [
@@ -61,6 +61,6 @@
},
"devDependencies": {
"@nhost/docgen": "workspace:*",
"graphql": "16.6.0"
"graphql": "16.7.1"
}
}

View File

@@ -1,5 +1,12 @@
# @nhost/hasura-auth-js
## 2.1.7
### Patch Changes
- 1d04ad630: chore(deps): use `fetch-ponyfill` instead of `isomorphic-unfetch`
- 7e973d568: fix(tokens): prevent infinite token refresh when using custom expiration
## 2.1.6
### Patch Changes

View File

@@ -1,8 +1,10 @@
import { faker } from '@faker-js/faker'
import fetch from 'isomorphic-unfetch'
import fetchPonyfill from 'fetch-ponyfill'
import { afterEach, describe, expect, it } from 'vitest'
import { auth, getHtmlLink, mailhog } from './helpers'
const { fetch } = fetchPonyfill()
describe('emails', () => {
afterEach(async () => {
await auth.signOut()

View File

@@ -1,9 +1,11 @@
import { load } from 'cheerio'
import fetch from 'isomorphic-unfetch'
import fetchPonyfill from 'fetch-ponyfill'
import createMailhogClient from 'mailhog'
import { expect } from 'vitest'
import { HasuraAuthClient, SignUpParams } from '../src'
const { fetch } = fetchPonyfill()
const AUTH_BACKEND_URL = 'https://local.auth.nhost.run/v1'
const auth = new HasuraAuthClient({

View File

@@ -1,8 +1,10 @@
import { faker } from '@faker-js/faker'
import fetch from 'isomorphic-unfetch'
import fetchPonyfill from 'fetch-ponyfill'
import { afterEach, describe, expect, it } from 'vitest'
import { auth, getHtmlLink, signUpAndInUser, signUpAndVerifyUser } from './helpers'
const { fetch } = fetchPonyfill()
describe('passwords', () => {
afterEach(async () => {
await auth.signOut()

View File

@@ -1,9 +1,11 @@
import { faker } from '@faker-js/faker'
import fetch from 'isomorphic-unfetch'
import fetchPonyfill from 'fetch-ponyfill'
import { afterEach, describe, expect, it } from 'vitest'
import { USER_ALREADY_SIGNED_IN } from '../src'
import { auth, getHtmlLink, signUpAndInUser, signUpAndVerifyUser } from './helpers'
const { fetch } = fetchPonyfill()
describe('sign-in', () => {
afterEach(async () => {
await auth.signOut()

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/hasura-auth-js",
"version": "2.1.6",
"version": "2.1.7",
"description": "Hasura-auth client",
"license": "MIT",
"keywords": [
@@ -65,7 +65,7 @@
},
"dependencies": {
"@simplewebauthn/browser": "^6.0.0",
"isomorphic-unfetch": "^3.1.0",
"fetch-ponyfill": "^7.1.0",
"js-cookie": "^3.0.1",
"jwt-decode": "^3.1.2",
"xstate": "^4.33.5"
@@ -76,6 +76,6 @@
"@types/js-cookie": "^3.0.2",
"cheerio": "1.0.0-rc.12",
"mailhog": "^4.16.0",
"msw": "^1.0.1"
"msw": "^1.2.2"
}
}

View File

@@ -8,6 +8,6 @@ export const MIN_PASSWORD_LENGTH = 3
* Minimum time in seconds between now and the JWT expiration time before the JWT is refreshed
* For instance, if set to 60, the client will refresh the JWT one minute before it expires
*/
export const TOKEN_REFRESH_MARGIN = 300 // five minutes
export const TOKEN_REFRESH_MARGIN_SECONDS = 60
export const REFRESH_TOKEN_MAX_ATTEMPTS = 5

View File

@@ -10,6 +10,7 @@ export type AuthContext = {
accessToken: {
value: string | null
expiresAt: Date | null
expiresInSeconds: number | null
}
refreshTimer: {
startedAt: Date | null
@@ -30,7 +31,8 @@ export const INITIAL_MACHINE_CONTEXT: AuthContext = {
mfa: null,
accessToken: {
value: null,
expiresAt: null
expiresAt: null,
expiresInSeconds: 15
},
refreshTimer: {
startedAt: null,

View File

@@ -11,7 +11,7 @@ import {
NHOST_REFRESH_TOKEN_ID_KEY,
NHOST_REFRESH_TOKEN_KEY,
REFRESH_TOKEN_MAX_ATTEMPTS,
TOKEN_REFRESH_MARGIN
TOKEN_REFRESH_MARGIN_SECONDS
} from '../../constants'
import {
CodifiedError,
@@ -548,13 +548,15 @@ export const createAuthMachine = ({
storageSetter(NHOST_JWT_EXPIRES_AT_KEY, nextRefresh.toISOString())
return {
value: accessToken,
expiresAt: nextRefresh
expiresAt: nextRefresh,
expiresInSeconds: accessTokenExpiresIn
}
}
storageSetter(NHOST_JWT_EXPIRES_AT_KEY, null)
return {
value: null,
expiresAt: null
expiresAt: null,
expiresInSeconds: null
}
},
refreshToken: (_, { data }) => {
@@ -582,13 +584,15 @@ export const createAuthMachine = ({
storageSetter(NHOST_JWT_EXPIRES_AT_KEY, nextRefresh.toISOString())
return {
value: accessToken,
expiresAt: nextRefresh
expiresAt: nextRefresh,
expiresInSeconds: accessTokenExpiresIn
}
}
storageSetter(NHOST_JWT_EXPIRES_AT_KEY, null)
return {
value: null,
expiresAt: null
expiresAt: null,
expiresInSeconds: null
}
},
refreshToken: (_, { data }) => {
@@ -704,10 +708,23 @@ export const createAuthMachine = ({
}
}
// * In any case, it's time to refresh when there's less than
// * TOKEN_REFRESH_MARGIN seconds before the JWT exprires
const expiresIn = expiresAt.getTime() - Date.now()
const remaining = expiresIn - 1_000 * TOKEN_REFRESH_MARGIN
return remaining <= 0
// * TOKEN_REFRESH_MARGIN_SECONDS seconds before the JWT exprires
const accessTokenExpirationTime = ctx.accessToken.expiresInSeconds
if (!accessTokenExpirationTime) {
return false
}
const expiresInMilliseconds = expiresAt.getTime() - Date.now()
// If the token expires in less time than the margin, we should use
// a margin based on the token expiration time to avoid refreshing
// the token infinitely
const remainingMilliseconds =
expiresInMilliseconds -
1_000 * Math.min(TOKEN_REFRESH_MARGIN_SECONDS, accessTokenExpirationTime * 0.5)
return remainingMilliseconds <= 0
},
// * Untyped action payload. See https://github.com/statelyai/xstate/issues/3037
/** Shoud retry to import the token on network error or any internal server error.

View File

@@ -1,4 +1,4 @@
import fetch from 'isomorphic-unfetch'
import fetchPonyfill from 'fetch-ponyfill'
import { NETWORK_ERROR_CODE } from '../errors'
import { NullableErrorResponse } from '../types'
@@ -6,6 +6,8 @@ interface FetcResponse<T> extends NullableErrorResponse {
data: T
}
const { fetch } = fetchPonyfill()
const fetchWrapper = async <T>(
url: string,
method: 'GET' | 'POST',

View File

@@ -6,7 +6,8 @@ export const contextWithUser: AuthContext = {
...INITIAL_MACHINE_CONTEXT,
accessToken: {
value: faker.datatype.string(40),
expiresAt: faker.date.future()
expiresAt: faker.date.future(),
expiresInSeconds: 15
},
refreshToken: {
value: faker.datatype.uuid()

View File

@@ -1,14 +1,14 @@
import { faker } from '@faker-js/faker'
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
import { interpret, InterpreterFrom } from 'xstate'
import { InterpreterFrom, interpret } from 'xstate'
import { waitFor } from 'xstate/lib/waitFor'
import {
AuthMachine,
createAuthMachine,
INVALID_REFRESH_TOKEN,
NHOST_JWT_EXPIRES_AT_KEY,
NHOST_REFRESH_TOKEN_KEY,
TOKEN_REFRESH_MARGIN
TOKEN_REFRESH_MARGIN_SECONDS,
createAuthMachine
} from '../src'
import { BASE_URL } from './helpers/config'
import {
@@ -68,7 +68,8 @@ describe(`Time based token refresh`, () => {
...contextWithUser,
accessToken: {
value: initialToken,
expiresAt: initialExpiration
expiresAt: initialExpiration,
expiresInSeconds: 900
}
})
@@ -105,7 +106,7 @@ describe(`Time based token refresh`, () => {
test(`access token should always be refreshed when reaching the expiration margin`, async () => {
// Fast forward to the initial expiration date
vi.setSystemTime(new Date(initialExpiration.getTime() - TOKEN_REFRESH_MARGIN * 1000))
vi.setSystemTime(new Date(initialExpiration.getTime() - TOKEN_REFRESH_MARGIN_SECONDS * 1000))
await waitFor(authServiceWithInitialSession, (state) =>
state.matches({ authentication: { signedIn: { refreshTimer: { running: 'refreshing' } } } })
@@ -126,7 +127,7 @@ describe(`Time based token refresh`, () => {
// Fast forward to the expiration date of the access token
vi.setSystemTime(
new Date(firstRefreshAccessTokenExpiration.getTime() - TOKEN_REFRESH_MARGIN * 1000)
new Date(firstRefreshAccessTokenExpiration.getTime() - TOKEN_REFRESH_MARGIN_SECONDS * 1000)
)
await waitFor(authServiceWithInitialSession, (state) =>
@@ -148,7 +149,9 @@ describe(`Time based token refresh`, () => {
// Fast forward to a time when the access token is still valid, so nothing should be refreshed
vi.setSystemTime(
new Date(secondRefreshAccessTokenExpiration.getTime() - TOKEN_REFRESH_MARGIN * 5 * 1000)
new Date(
secondRefreshAccessTokenExpiration.getTime() - TOKEN_REFRESH_MARGIN_SECONDS * 5 * 1000
)
)
const thirdRefreshState = await waitFor(authServiceWithInitialSession, (state) =>
@@ -165,7 +168,7 @@ describe(`Time based token refresh`, () => {
})
test(`token should be refreshed every N seconds based on the refresh interval`, async () => {
const refreshIntervalTime = faker.datatype.number({ min: 800, max: 900 })
const refreshIntervalTime = faker.datatype.number({ min: 1000, max: 1500 })
const authMachineWithInitialSession = createAuthMachine({
backendUrl: BASE_URL,
@@ -178,7 +181,8 @@ describe(`Time based token refresh`, () => {
...contextWithUser,
accessToken: {
value: initialToken,
expiresAt: initialExpiration
expiresAt: initialExpiration,
expiresInSeconds: 900
}
})
@@ -249,6 +253,7 @@ describe('General and disabled auto-sign in', () => {
const user = { ...fakeUser }
const accessToken = faker.datatype.string(40)
const refreshToken = faker.datatype.uuid()
const accessTokenExpiresIn = 900
server.use(authTokenNetworkErrorHandler)
@@ -257,13 +262,16 @@ describe('General and disabled auto-sign in', () => {
data: {
session: {
accessToken,
accessTokenExpiresIn: 0,
accessTokenExpiresIn,
refreshToken,
user
}
}
})
// Fast forward to a time when the access token is already expired
vi.setSystemTime(Date.now() + accessTokenExpiresIn * 1.5 * 1000)
const state = await waitFor(authService, (state) => state.context.refreshTimer.attempts > 0)
expect(state.context.refreshTimer.attempts).toBeGreaterThan(0)
}, 8000)

View File

@@ -2,7 +2,7 @@ import { faker } from '@faker-js/faker'
import { afterAll, afterEach, beforeAll, beforeEach, expect, test } from 'vitest'
import { interpret } from 'xstate'
import { waitFor } from 'xstate/lib/waitFor'
import { AuthClient, createSendVerificationEmailMachine, INVALID_EMAIL_ERROR } from '../src'
import { AuthClient, INVALID_EMAIL_ERROR, createSendVerificationEmailMachine } from '../src'
import { BASE_URL } from './helpers/config'
import {
sendVerificationEmailInternalErrorHandler,

View File

@@ -1,5 +1,11 @@
# @nhost/hasura-storage-js
## 2.1.6
### Patch Changes
- 1d04ad630: chore(deps): use `fetch-ponyfill` instead of `isomorphic-unfetch`
## 2.1.5
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/hasura-storage-js",
"version": "2.1.5",
"version": "2.1.6",
"description": "Hasura-storage client",
"license": "MIT",
"keywords": [

View File

@@ -1,5 +1,17 @@
# @nhost/nextjs
## 1.13.30
### Patch Changes
- @nhost/react@2.0.24
## 1.13.29
### Patch Changes
- @nhost/react@2.0.23
## 1.13.28
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/nextjs",
"version": "1.13.28",
"version": "1.13.30",
"description": "Nhost NextJS library",
"license": "MIT",
"keywords": [

View File

@@ -1,9 +1,9 @@
import {
AuthMachine,
NHOST_REFRESH_TOKEN_KEY,
NhostClient,
NhostReactClientConstructorParams,
NhostSession,
NHOST_REFRESH_TOKEN_KEY,
VanillaNhostClient
} from '@nhost/react'
import Cookies from 'js-cookie'
@@ -12,9 +12,11 @@ import { StateFrom } from 'xstate'
import { waitFor } from 'xstate/lib/waitFor'
import { NHOST_SESSION_KEY } from './utils'
export type CreateServerSideClientParams = Pick<
NhostReactClientConstructorParams,
'subdomain' | 'region' | 'authUrl' | 'functionsUrl' | 'graphqlUrl' | 'storageUrl'
export type CreateServerSideClientParams = Partial<
Pick<
NhostReactClientConstructorParams,
'subdomain' | 'region' | 'authUrl' | 'functionsUrl' | 'graphqlUrl' | 'storageUrl'
>
>
/**

View File

@@ -1,5 +1,23 @@
# @nhost/nhost-js
## 2.2.10
### Patch Changes
- 07a45fde0: chore(deps): bump `graphql` to `v16.7.1`
- Updated dependencies [07a45fde0]
- @nhost/graphql-js@0.1.4
## 2.2.9
### Patch Changes
- 5a4e237a2: fix(deps): pass access token to clients on sign in
- Updated dependencies [1d04ad630]
- Updated dependencies [7e973d568]
- @nhost/hasura-auth-js@2.1.7
- @nhost/hasura-storage-js@2.1.6
## 2.2.8
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/nhost-js",
"version": "2.2.8",
"version": "2.2.10",
"description": "Nhost JavaScript SDK",
"license": "MIT",
"keywords": [
@@ -69,7 +69,7 @@
},
"devDependencies": {
"@nhost/docgen": "workspace:*",
"graphql": "16.6.0"
"graphql": "16.7.1"
},
"peerDependencies": {
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"

View File

@@ -52,12 +52,19 @@ export class NhostClient {
this.functions = createFunctionsClient({ adminSecret, ...urlParams })
this.graphql = createGraphqlClient({ adminSecret, ...urlParams })
this.auth.onAuthStateChanged((_event, session) => {
if (_event === 'SIGNED_OUT') {
this.auth.onAuthStateChanged((event, session) => {
if (event === 'SIGNED_OUT') {
this.storage.setAccessToken(undefined)
this.functions.setAccessToken(undefined)
this.graphql.setAccessToken(undefined)
return
}
const accessToken = session?.accessToken
this.storage.setAccessToken(accessToken)
this.functions.setAccessToken(accessToken)
this.graphql.setAccessToken(accessToken)
})
// * Update access token for clients, including when signin in

View File

@@ -1,5 +1,19 @@
# @nhost/react
## 2.0.24
### Patch Changes
- Updated dependencies [07a45fde0]
- @nhost/nhost-js@2.2.10
## 2.0.23
### Patch Changes
- Updated dependencies [5a4e237a2]
- @nhost/nhost-js@2.2.9
## 2.0.22
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/react",
"version": "2.0.22",
"version": "2.0.24",
"description": "Nhost React library",
"license": "MIT",
"keywords": [

View File

@@ -1,5 +1,19 @@
# @nhost/vue
## 1.13.30
### Patch Changes
- Updated dependencies [07a45fde0]
- @nhost/nhost-js@2.2.10
## 1.13.29
### Patch Changes
- Updated dependencies [5a4e237a2]
- @nhost/nhost-js@2.2.9
## 1.13.28
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@nhost/vue",
"version": "1.13.28",
"version": "1.13.30",
"description": "Nhost Vue library",
"license": "MIT",
"keywords": [

1716
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff