Compare commits
14 Commits
@nhost/das
...
@nhost/das
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b25c37c26 | ||
|
|
6df4f02e95 | ||
|
|
aaae98f019 | ||
|
|
dc23dc0f49 | ||
|
|
82728da100 | ||
|
|
2d68fee54c | ||
|
|
35010353c7 | ||
|
|
aff059ec71 | ||
|
|
713d53cfc0 | ||
|
|
e0ab6d9a37 | ||
|
|
7baee8a9cc | ||
|
|
3db2999f60 | ||
|
|
3c4dd55045 | ||
|
|
92b434e840 |
@@ -1,5 +1,32 @@
|
||||
# @nhost/dashboard
|
||||
|
||||
## 1.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6df4f02: fix: use custom error toast and show correct message when sending an invite
|
||||
|
||||
## 1.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react-apollo@9.0.2
|
||||
- @nhost/nextjs@2.1.4
|
||||
|
||||
## 1.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 713d53c: feat: add catch-all route for workspace/project - useful for documentation
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 3db2999: fix: refresh table list after running SQL using the editor
|
||||
- 3c4dd55: fix: handle `Error` objects properly in the `ErrorToast` component
|
||||
- 92b434e: fix: resolve an issue where the checkbox in the data-grid header did not select all rows
|
||||
- @nhost/react-apollo@9.0.1
|
||||
- @nhost/nextjs@2.1.3
|
||||
|
||||
## 1.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/dashboard",
|
||||
"version": "1.7.0",
|
||||
"version": "1.8.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
|
||||
@@ -96,45 +96,52 @@ export default function DataGridHeader<T extends object>({
|
||||
}}
|
||||
key={column.id}
|
||||
>
|
||||
<Dropdown.Trigger
|
||||
className={twMerge(
|
||||
'focus:outline-none motion-safe:transition-colors',
|
||||
)}
|
||||
disabled={
|
||||
column.isDisabled ||
|
||||
column.id === 'selection' ||
|
||||
(column.disableSortBy && !onRemoveColumn)
|
||||
}
|
||||
hideChevron
|
||||
>
|
||||
{column.id === 'selection' ? (
|
||||
<span
|
||||
{...headerProps}
|
||||
className="relative grid w-full grid-flow-col items-center justify-between p-2"
|
||||
>
|
||||
{column.render('Header')}
|
||||
|
||||
{allowSort && (
|
||||
<Box component="span" sx={{ color: 'text.primary' }}>
|
||||
{column.isSorted && !column.isSortedDesc && (
|
||||
<ArrowUpIcon className="h-3 w-3" />
|
||||
)}
|
||||
|
||||
{column.isSorted && column.isSortedDesc && (
|
||||
<ArrowDownIcon className="h-3 w-3" />
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</span>
|
||||
|
||||
{allowResize && !column.disableResizing && (
|
||||
) : (
|
||||
<Dropdown.Trigger
|
||||
className={twMerge(
|
||||
'focus:outline-none motion-safe:transition-colors',
|
||||
)}
|
||||
disabled={
|
||||
column.isDisabled || (column.disableSortBy && !onRemoveColumn)
|
||||
}
|
||||
hideChevron
|
||||
>
|
||||
<span
|
||||
{...column.getResizerProps({
|
||||
onClick: (event: Event) => event.stopPropagation(),
|
||||
})}
|
||||
className="absolute top-0 bottom-0 -right-0.5 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors"
|
||||
/>
|
||||
)}
|
||||
</Dropdown.Trigger>
|
||||
{...headerProps}
|
||||
className="relative grid w-full grid-flow-col items-center justify-between p-2"
|
||||
>
|
||||
{column.render('Header')}
|
||||
|
||||
{allowSort && (
|
||||
<Box component="span" sx={{ color: 'text.primary' }}>
|
||||
{column.isSorted && !column.isSortedDesc && (
|
||||
<ArrowUpIcon className="h-3 w-3" />
|
||||
)}
|
||||
|
||||
{column.isSorted && column.isSortedDesc && (
|
||||
<ArrowDownIcon className="h-3 w-3" />
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</span>
|
||||
|
||||
{allowResize && !column.disableResizing && (
|
||||
<span
|
||||
{...column.getResizerProps({
|
||||
onClick: (event: Event) => event.stopPropagation(),
|
||||
})}
|
||||
className="absolute -right-0.5 bottom-0 top-0 z-10 h-full w-1.5 group-hover:bg-slate-900 group-hover:bg-opacity-20 group-active:bg-slate-900 group-active:bg-opacity-20 motion-safe:transition-colors"
|
||||
/>
|
||||
)}
|
||||
</Dropdown.Trigger>
|
||||
)}
|
||||
|
||||
<Dropdown.Content
|
||||
menu
|
||||
|
||||
@@ -5,7 +5,7 @@ import { XIcon } from '@/components/ui/v2/icons/XIcon';
|
||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||
import { getToastBackgroundColor } from '@/utils/constants/settings';
|
||||
import { copy } from '@/utils/copy';
|
||||
import { type ApolloError } from '@apollo/client';
|
||||
import type { ApolloError } from '@apollo/client';
|
||||
import { useUserData } from '@nhost/nextjs';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -20,6 +20,44 @@ interface ErrorDetails {
|
||||
error: any;
|
||||
}
|
||||
|
||||
const getInternalErrorMessage = (
|
||||
error: Error | ApolloError | undefined,
|
||||
): string | null => {
|
||||
if (!error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (error.name === 'ApolloError') {
|
||||
// @ts-ignore
|
||||
const internalError = error.graphQLErrors?.[0]?.extensions?.internal as {
|
||||
error: { message: string };
|
||||
};
|
||||
return internalError?.error?.message || null;
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const errorToObject = (error: ApolloError | Error) => {
|
||||
if (error.name === 'ApolloError') {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
return {
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
export default function ErrorToast({
|
||||
isVisible,
|
||||
errorMessage,
|
||||
@@ -28,7 +66,7 @@ export default function ErrorToast({
|
||||
}: {
|
||||
isVisible: boolean;
|
||||
errorMessage: string;
|
||||
error: ApolloError;
|
||||
error: ApolloError | Error;
|
||||
close: () => void;
|
||||
}) {
|
||||
const userData = useUserData();
|
||||
@@ -43,19 +81,10 @@ export default function ErrorToast({
|
||||
userId: userData?.id || 'local',
|
||||
url: asPath,
|
||||
},
|
||||
error,
|
||||
error: errorToObject(error),
|
||||
};
|
||||
|
||||
const internalError = error?.graphQLErrors?.at(0)?.extensions?.internal as {
|
||||
error: {
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
|
||||
const msg =
|
||||
internalError?.error?.message ||
|
||||
error?.graphQLErrors?.at(0).message ||
|
||||
errorMessage;
|
||||
const msg = getInternalErrorMessage(error) || errorMessage;
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useDatabaseQuery } from '@/features/database/dataGrid/hooks/useDatabaseQuery';
|
||||
import { useCurrentWorkspaceAndProject } from '@/features/projects/common/hooks/useCurrentWorkspaceAndProject';
|
||||
import { generateAppServiceUrl } from '@/features/projects/common/utils/generateAppServiceUrl';
|
||||
import { getToastStyleProps } from '@/utils/constants/settings';
|
||||
import { getHasuraAdminSecret } from '@/utils/env';
|
||||
import { parseIdentifiersFromSQL } from '@/utils/sql';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
export default function useRunSQL(
|
||||
sqlCode: string,
|
||||
@@ -22,6 +24,14 @@ export default function useRunSQL(
|
||||
const [columns, setColumns] = useState<string[]>([]);
|
||||
const [rows, setRows] = useState<string[][]>([[]]);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
query: { dataSourceSlug },
|
||||
} = router;
|
||||
|
||||
const { refetch } = useDatabaseQuery([dataSourceSlug as string]);
|
||||
|
||||
const appUrl = generateAppServiceUrl(
|
||||
currentProject?.subdomain,
|
||||
currentProject?.region,
|
||||
@@ -269,6 +279,9 @@ export default function useRunSQL(
|
||||
}
|
||||
}
|
||||
|
||||
// refresh the table list after running the sql
|
||||
await refetch();
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useIsCurrentUserOwner } from '@/features/projects/common/hooks/useIsCur
|
||||
import { PendingWorkspaceMemberInvitation } from '@/features/projects/workspaces/components/PendingWorkspaceMemberInvitation';
|
||||
import { WorkspaceMember } from '@/features/projects/workspaces/components/WorkspaceMember';
|
||||
import { discordAnnounce } from '@/utils/discordAnnounce';
|
||||
import { getErrorMessage } from '@/utils/getErrorMessage';
|
||||
import { execPromiseWithErrorToast } from '@/utils/execPromiseWithErrorToast';
|
||||
import { triggerToast } from '@/utils/toast';
|
||||
import {
|
||||
refetchGetWorkspaceMembersQuery,
|
||||
@@ -52,38 +52,42 @@ function WorkspaceMemberInviteForm({
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await insertWorkspaceMemberInvite({
|
||||
variables: {
|
||||
workspaceMemberInvite: {
|
||||
workspaceId: currentWorkspace.id,
|
||||
email,
|
||||
memberType: 'member',
|
||||
await execPromiseWithErrorToast(
|
||||
async () => {
|
||||
await insertWorkspaceMemberInvite({
|
||||
variables: {
|
||||
workspaceMemberInvite: {
|
||||
workspaceId: currentWorkspace.id,
|
||||
email,
|
||||
memberType: 'member',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
triggerToast(
|
||||
`Invite to join workspace ${currentWorkspace.name} sent to ${email}.`,
|
||||
);
|
||||
} catch (error) {
|
||||
await discordAnnounce(
|
||||
`Error trying to invite to ${email} to ${currentWorkspace.name} ${error.message}`,
|
||||
);
|
||||
if (
|
||||
error.message ===
|
||||
'Foreign key violation. insert or update on table "workspace_member_invites" violates foreign key constraint "workspace_member_invites_email_fkey"'
|
||||
) {
|
||||
setWorkspaceInviteError(
|
||||
'You can only invite users that are already registered at Nhost. Ask the person to register an account, then invite them again.',
|
||||
});
|
||||
|
||||
triggerToast(
|
||||
`Invite to join workspace ${currentWorkspace.name} sent to ${email}.`,
|
||||
);
|
||||
},
|
||||
{
|
||||
loadingMessage: 'Sending invite...',
|
||||
successMessage: 'The invite has been sent successfully.',
|
||||
errorMessage: `Error trying to invite to ${email} to ${currentWorkspace.name}`,
|
||||
onError: async (error) => {
|
||||
await discordAnnounce(
|
||||
`Error trying to invite to ${email} to ${currentWorkspace.name} ${error.message}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setWorkspaceInviteError(getErrorMessage(error, 'invite'));
|
||||
|
||||
return;
|
||||
}
|
||||
if (
|
||||
error.message ===
|
||||
'Foreign key violation. insert or update on table "workspace_member_invites" violates foreign key constraint "workspace_member_invites_email_fkey"'
|
||||
) {
|
||||
setWorkspaceInviteError(
|
||||
'You can only invite users that are already registered at Nhost. Ask the person to register an account, then invite them again.',
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
setEmail('');
|
||||
};
|
||||
@@ -130,8 +134,8 @@ export default function WorkspaceMembers() {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mx-auto mt-18 max-w-3xl font-display">
|
||||
<div className="mb-2 grid grid-flow-row gap-1">
|
||||
<div className="max-w-3xl mx-auto mt-18 font-display">
|
||||
<div className="grid grid-flow-row gap-1 mb-2">
|
||||
<Text variant="h3">Members</Text>
|
||||
<Text color="secondary" className="text-sm">
|
||||
People in this workspace can manage all projects listed above.
|
||||
|
||||
158
dashboard/src/pages/_/_/[...slug].tsx
Normal file
158
dashboard/src/pages/_/_/[...slug].tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
import { AuthenticatedLayout } from '@/components/layout/AuthenticatedLayout';
|
||||
import { Container } from '@/components/layout/Container';
|
||||
import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary';
|
||||
import { ActivityIndicator } from '@/components/ui/v2/ActivityIndicator';
|
||||
import { Box } from '@/components/ui/v2/Box';
|
||||
import { Button } from '@/components/ui/v2/Button';
|
||||
import { Input } from '@/components/ui/v2/Input';
|
||||
import { List } from '@/components/ui/v2/List';
|
||||
import { ListItem } from '@/components/ui/v2/ListItem';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import {
|
||||
useGetAllWorkspacesAndProjectsQuery,
|
||||
type GetAllWorkspacesAndProjectsQuery,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { Divider } from '@mui/material';
|
||||
import { useUserData } from '@nhost/nextjs';
|
||||
import debounce from 'lodash.debounce';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { ChangeEvent, ReactElement } from 'react';
|
||||
import { Fragment, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
type Workspace = Omit<
|
||||
GetAllWorkspacesAndProjectsQuery['workspaces'][0],
|
||||
'__typename'
|
||||
>;
|
||||
|
||||
export default function SelectWorkspaceAndProject() {
|
||||
const user = useUserData();
|
||||
const router = useRouter();
|
||||
|
||||
const { data, loading } = useGetAllWorkspacesAndProjectsQuery({
|
||||
skip: !user,
|
||||
});
|
||||
|
||||
const workspaces: Workspace[] = data?.workspaces || [];
|
||||
|
||||
const projects = workspaces.flatMap((workspace) =>
|
||||
workspace.projects.map((project) => ({
|
||||
workspaceName: workspace.name,
|
||||
projectName: project.name,
|
||||
value: `${workspace.slug}/${project.slug}`,
|
||||
})),
|
||||
);
|
||||
|
||||
const [filter, setFilter] = useState('');
|
||||
|
||||
const handleFilterChange = useMemo(
|
||||
() =>
|
||||
debounce((event: ChangeEvent<HTMLInputElement>) => {
|
||||
setFilter(event.target.value);
|
||||
}, 200),
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => () => handleFilterChange.cancel(), [handleFilterChange]);
|
||||
|
||||
const goToProjectPage = async (project: {
|
||||
workspaceName: string;
|
||||
projectName: string;
|
||||
value: string;
|
||||
}) => {
|
||||
const { slug } = router.query;
|
||||
|
||||
await router.push({
|
||||
pathname: `/${project.value}/${
|
||||
Array.isArray(slug) ? slug.join('/') : slug
|
||||
}`,
|
||||
});
|
||||
};
|
||||
|
||||
const projectsToDisplay = filter
|
||||
? projects.filter((project) =>
|
||||
project.projectName.toLowerCase().includes(filter.toLowerCase()),
|
||||
)
|
||||
: projects;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex w-full justify-center">
|
||||
<ActivityIndicator
|
||||
delay={500}
|
||||
label="Loading workspaces and projects..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="mx-auto grid max-w-[760px] grid-flow-row gap-4 py-6 sm:py-14">
|
||||
<Text variant="h2" component="h1" className="">
|
||||
Select a Project
|
||||
</Text>
|
||||
|
||||
<div>
|
||||
<div className="mb-2 flex w-full">
|
||||
<Input
|
||||
placeholder="Search..."
|
||||
onChange={handleFilterChange}
|
||||
fullWidth
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<RetryableErrorBoundary>
|
||||
{projectsToDisplay.length === 0 ? (
|
||||
<Box className="h-import py-2">
|
||||
<Text variant="subtitle2">No results found.</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<List className="h-import overflow-y-auto">
|
||||
{projectsToDisplay.map((project, index) => (
|
||||
<Fragment key={project.value}>
|
||||
<ListItem.Root
|
||||
className="grid grid-flow-col justify-start gap-2 py-2.5"
|
||||
secondaryAction={
|
||||
<Button
|
||||
variant="borderless"
|
||||
color="primary"
|
||||
onClick={() => goToProjectPage(project)}
|
||||
>
|
||||
Select
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<ListItem.Avatar>
|
||||
<span className="inline-block h-6 w-6 overflow-hidden rounded-md">
|
||||
<Image
|
||||
src="/logos/new.svg"
|
||||
alt="Nhost Logo"
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
</span>
|
||||
</ListItem.Avatar>
|
||||
<ListItem.Text
|
||||
primary={project.projectName}
|
||||
secondary={`${project.workspaceName} / ${project.projectName}`}
|
||||
/>
|
||||
</ListItem.Root>
|
||||
|
||||
{index < projects.length - 1 && <Divider component="li" />}
|
||||
</Fragment>
|
||||
))}
|
||||
</List>
|
||||
)}
|
||||
</RetryableErrorBoundary>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
SelectWorkspaceAndProject.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AuthenticatedLayout title="Select a Project">{page}</AuthenticatedLayout>
|
||||
);
|
||||
};
|
||||
@@ -29,6 +29,7 @@ import { Toaster } from 'react-hot-toast';
|
||||
const emotionCache = createEmotionCache();
|
||||
|
||||
process.env = {
|
||||
TEST_MODE: 'true',
|
||||
NODE_ENV: 'development',
|
||||
NEXT_PUBLIC_NHOST_PLATFORM: 'false',
|
||||
NEXT_PUBLIC_ENV: 'dev',
|
||||
|
||||
@@ -29,6 +29,7 @@ export default async function execPromiseWithErrorToast(
|
||||
const result = await call();
|
||||
|
||||
toast.dismiss(loadingToastId);
|
||||
|
||||
toast.success(successMessage, {
|
||||
style: toastStyle.style,
|
||||
...toastStyle.success,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/docs
|
||||
|
||||
## 2.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- dc23dc0: fix: docs run references
|
||||
|
||||
## 2.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -9,7 +9,7 @@ If you are using the Nhost CLI for local development, as of [v0.12.0](https://gi
|
||||
|
||||
<Steps>
|
||||
<Step title="Configuring the Service">
|
||||
Follow the steps highlighed in the ["Enabling Service"](enabling-service) guide and don't forget to add the relevant secrets to your `.secrets` file.
|
||||
Follow the steps highlighed in the [Enabling Service](enabling-service) guide and don't forget to add the relevant secrets to your `.secrets` file.
|
||||
</Step>
|
||||
<Step title="Start nhost">
|
||||
Run `nhost up`:
|
||||
|
||||
@@ -46,11 +46,11 @@ capacity=1
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Info>Head to [CLI & CI deployments](/run/ci) for more details on how to deploy using a configuration file.</Info>
|
||||
<Info>Head to [CLI & CI deployments](/guides/run/cli-deployments) for more details on how to deploy using a configuration file.</Info>
|
||||
|
||||
The `name` of the service is used as an identifier and to generate URLs when exposing the service to the Internet. You can use any container image publicly available or you can push your own to the [Nhost registry](/run/registry).
|
||||
The `name` of the service is used as an identifier and to generate URLs when exposing the service to the Internet. You can use any container image publicly available or you can push your own to the [Nhost registry](/guides/run/registry).
|
||||
|
||||
All environment variables set here are exclusive to this service and will not be shared with other services or with the Nhost stack. If you are using a configuration file secrets are supported.
|
||||
|
||||
For more details about the `Ports` section head to [networking](/run/networking). You can also head to [resources](/run/resources) for more information about replicas, compute, and storage.
|
||||
For more details about the `Ports` section head to [networking](/guides/run/networking). You can also head to [resources](/guides/run/resources) for more information about replicas, compute, and storage.
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ Then on `New Service`:
|
||||
|
||||

|
||||
|
||||
Now you can fill your [service configuration](/run/configuration):
|
||||
Now you can fill your [service configuration](/guides/run/configuration):
|
||||
|
||||

|
||||
|
||||
As you configure the `Ports` section you can take note of the generated URL. You can find more information about this section under [Networking](/run/networking).
|
||||
As you configure the `Ports` section you can take note of the generated URL. You can find more information about this section under [Networking](/guides/run/networking).
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ To pause a service, simply set its number of replicas to `0`:
|
||||
<Tab title="dashboard">
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
</Tab>
|
||||
<Tab title="toml">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/docs",
|
||||
"version": "2.5.0",
|
||||
"version": "2.6.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "mintlify dev"
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost-examples/cli
|
||||
|
||||
## 0.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.6
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/cli",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.8",
|
||||
"main": "src/index.mjs",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @nhost-examples/codegen-react-apollo
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
- @nhost/react-apollo@9.0.2
|
||||
|
||||
## 0.1.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react-apollo@9.0.1
|
||||
- @nhost/react@3.2.1
|
||||
|
||||
## 0.1.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-apollo",
|
||||
"version": "0.1.14",
|
||||
"version": "0.1.16",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"codegen": "graphql-codegen",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost-examples/codegen-react-query
|
||||
|
||||
## 0.1.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.1
|
||||
|
||||
## 0.1.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-query",
|
||||
"version": "0.1.15",
|
||||
"version": "0.1.17",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"codegen": "graphql-codegen",
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @nhost-examples/react-urql
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
- @nhost/react-urql@6.0.2
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.1
|
||||
- @nhost/react-urql@6.0.1
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/codegen-react-urql",
|
||||
"private": true,
|
||||
"version": "0.0.11",
|
||||
"version": "0.0.13",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost-examples/docker-compose
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- aff059e: fix: timers
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -42,6 +42,13 @@ services:
|
||||
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: public
|
||||
HASURA_GRAPHQL_LOG_LEVEL: debug
|
||||
HASURA_GRAPHQL_ENABLE_CONSOLE: 'true'
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- curl http://localhost:8080/healthz > /dev/null 2>&1
|
||||
timeout: 60s
|
||||
interval: 30s
|
||||
start_period: 90s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.hasura.rule=Host(`${PROXY_HOST}`, `localhost`) && PathPrefix(`/`)"
|
||||
@@ -66,7 +73,7 @@ services:
|
||||
AUTH_SMTP_USER: user
|
||||
AUTH_SMTP_PASS: password
|
||||
AUTH_SMTP_SENDER: mail@example.com
|
||||
expose:
|
||||
expose:
|
||||
- 4000
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
@@ -112,7 +119,7 @@ services:
|
||||
- "traefik.http.routers.functions.middlewares=strip-functions@docker"
|
||||
- "traefik.http.routers.functions.entrypoints=web"
|
||||
restart: always
|
||||
expose:
|
||||
expose:
|
||||
- 3000
|
||||
volumes:
|
||||
- .:/opt/project
|
||||
@@ -140,7 +147,7 @@ services:
|
||||
SMTP_SECURE: "${AUTH_SMTP_SECURE:-false}"
|
||||
SMTP_SENDER: ${AUTH_SMTP_SENDER:-hbp@hbp.com}
|
||||
ports:
|
||||
- ${AUTH_SMTP_PORT:-1025}:1025
|
||||
- ${AUTH_SMTP_PORT:-1025}:1025
|
||||
- 8025:8025
|
||||
volumes:
|
||||
- ./data/mailhog:/maildir
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/docker-compose",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"e2e": "vitest run"
|
||||
|
||||
@@ -11,8 +11,12 @@ describe(
|
||||
beforeAll(async () => {
|
||||
// * Start docker compose
|
||||
await promisifiedExec(
|
||||
'docker compose -f docker-compose.yaml --env-file .env.example up --wait --quiet-pull'
|
||||
'docker compose -f docker-compose.yaml --env-file .env.example up --wait --wait-timeout 300 --quiet-pull'
|
||||
)
|
||||
|
||||
// we wait a bit extra because sometimes traefik takes a bit to configure the services
|
||||
setTimeout(() => {}, 30000);
|
||||
|
||||
}, 5 * 60 * 1000)
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost-examples/multi-tenant-one-to-many
|
||||
|
||||
## 2.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
|
||||
## 2.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.6
|
||||
|
||||
## 2.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/multi-tenant-one-to-many",
|
||||
"private": true,
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.6",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {},
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @nhost-examples/nextjs
|
||||
|
||||
## 0.1.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
- @nhost/react-apollo@9.0.2
|
||||
- @nhost/nextjs@2.1.4
|
||||
|
||||
## 0.1.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react-apollo@9.0.1
|
||||
- @nhost/react@3.2.1
|
||||
- @nhost/nextjs@2.1.3
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/nextjs",
|
||||
"version": "0.1.16",
|
||||
"version": "0.1.18",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost-examples/node-storage
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.6
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/node-storage",
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.10",
|
||||
"private": true,
|
||||
"description": "This is an example of how to use the Storage with Node.js",
|
||||
"main": "src/index.mjs",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost-examples/nextjs-server-components
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.6
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/nextjs-server-components",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @nhost-examples/react-apollo
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
- @nhost/react-apollo@9.0.2
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react-apollo@9.0.1
|
||||
- @nhost/react@3.2.1
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-apollo",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.2",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.9.4",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost-examples/react-gqty
|
||||
|
||||
## 1.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
|
||||
## 1.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.1
|
||||
|
||||
## 1.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-gqty",
|
||||
"private": true,
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# @nhost-examples/vue-apollo
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
- @nhost/apollo@6.0.7
|
||||
- @nhost/vue@2.2.2
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e0ab6d9]
|
||||
- @nhost/apollo@6.0.6
|
||||
- @nhost/nhost-js@3.0.6
|
||||
- @nhost/vue@2.2.1
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/vue-apollo",
|
||||
"private": true,
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.3",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @nhost-examples/vue-quickstart
|
||||
|
||||
## 0.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/apollo@6.0.7
|
||||
- @nhost/vue@2.2.2
|
||||
|
||||
## 0.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e0ab6d9]
|
||||
- @nhost/apollo@6.0.6
|
||||
- @nhost/vue@2.2.1
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/vue-quickstart",
|
||||
"version": "0.0.13",
|
||||
"version": "0.0.15",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @nhost/apollo
|
||||
|
||||
## 6.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
|
||||
## 6.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e0ab6d9: fix: add extra logic to check and wait for a valid JWT
|
||||
- @nhost/nhost-js@3.0.6
|
||||
|
||||
## 6.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/apollo",
|
||||
"version": "6.0.5",
|
||||
"version": "6.0.7",
|
||||
"description": "Nhost Apollo Client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@@ -65,7 +65,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"graphql": "16.8.1",
|
||||
"graphql-ws": "^5.14.3"
|
||||
"graphql-ws": "^5.14.3",
|
||||
"jwt-decode": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apollo/client": "^3.9.4",
|
||||
|
||||
@@ -12,6 +12,7 @@ import { setContext } from '@apollo/client/link/context'
|
||||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
|
||||
import { getMainDefinition } from '@apollo/client/utilities'
|
||||
import { AuthContext, NhostClient } from '@nhost/nhost-js'
|
||||
import jwtDecode, { JwtPayload } from 'jwt-decode'
|
||||
|
||||
import { createRestartableClient } from './ws'
|
||||
const isBrowser = typeof window !== 'undefined'
|
||||
@@ -58,25 +59,41 @@ export const createApolloClient = ({
|
||||
|
||||
let accessToken: AuthContext['accessToken'] | null = null
|
||||
|
||||
const isJwtValid = () => {
|
||||
if (!accessToken?.value) {
|
||||
return false
|
||||
}
|
||||
|
||||
const marginInSeconds = 3
|
||||
const marginInMilliseconds = marginInSeconds * 1000
|
||||
|
||||
let decodedToken: JwtPayload = jwtDecode(accessToken.value)
|
||||
return decodedToken.exp! * 1000 > Date.now() - marginInMilliseconds
|
||||
}
|
||||
|
||||
const isTokenValid = () =>
|
||||
!!accessToken?.value && !!accessToken?.expiresAt && accessToken?.expiresAt > new Date()
|
||||
!!accessToken?.value &&
|
||||
!!accessToken?.expiresAt &&
|
||||
accessToken?.expiresAt > new Date() &&
|
||||
isJwtValid()
|
||||
|
||||
const isTokenValidOrNull = () => !accessToken || isTokenValid()
|
||||
|
||||
const awaitValidTokenOrNull = () => {
|
||||
if (isTokenValidOrNull()) {
|
||||
return
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
// doing this as an interval to avoid race conditions.
|
||||
const interval = setInterval(() => {
|
||||
if (isTokenValidOrNull()) {
|
||||
clearInterval(interval)
|
||||
resolve(true)
|
||||
}
|
||||
}, 100)
|
||||
})
|
||||
const waitForValidToken = () => {
|
||||
if (isTokenValidOrNull()) {
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => waitForValidToken().then(resolve), 100)
|
||||
})
|
||||
}
|
||||
|
||||
return waitForValidToken()
|
||||
}
|
||||
|
||||
const getAuthHeaders = async () => {
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @nhost/react-apollo
|
||||
|
||||
## 9.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/apollo@6.0.7
|
||||
- @nhost/react@3.2.2
|
||||
|
||||
## 9.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e0ab6d9]
|
||||
- @nhost/apollo@6.0.6
|
||||
- @nhost/react@3.2.1
|
||||
|
||||
## 9.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-apollo",
|
||||
"version": "9.0.0",
|
||||
"version": "9.0.2",
|
||||
"description": "Nhost React Apollo client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost/react-urql
|
||||
|
||||
## 6.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
|
||||
## 6.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.1
|
||||
|
||||
## 6.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-urql",
|
||||
"version": "6.0.0",
|
||||
"version": "6.0.2",
|
||||
"description": "Nhost React URQL client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost/graphql-js
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2d68fee: fix: resolve an issue where unauthenticated graphql requests are not sent
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e0ab6d9: fix: add extra logic to check and wait for a valid JWT
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/graphql-js",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.7",
|
||||
"description": "Nhost GraphQL client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@@ -54,7 +54,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@graphql-typed-document-node/core": "^3.2.0",
|
||||
"isomorphic-unfetch": "^3.1.0"
|
||||
"isomorphic-unfetch": "^3.1.0",
|
||||
"jwt-decode": "^3.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
Variables
|
||||
} from './types'
|
||||
|
||||
import jwtDecode, { JwtPayload } from 'jwt-decode'
|
||||
|
||||
/**
|
||||
* @alias GraphQL
|
||||
*/
|
||||
@@ -28,6 +30,37 @@ export class NhostGraphqlClient {
|
||||
this.adminSecret = adminSecret
|
||||
}
|
||||
|
||||
private isAccessTokenValidOrNull = () => {
|
||||
if (!this.accessToken) {
|
||||
return true
|
||||
}
|
||||
|
||||
try {
|
||||
const decodedToken: JwtPayload = jwtDecode(this.accessToken)
|
||||
return decodedToken.exp != null && decodedToken.exp * 1000 > Date.now()
|
||||
} catch (error) {
|
||||
console.error('Error decoding token:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private awaitForValidAccessTokenOrNull = async () => {
|
||||
if (this.isAccessTokenValidOrNull()) {
|
||||
return true
|
||||
}
|
||||
|
||||
const waitForValidTokenOrNull = () => {
|
||||
if (this.isAccessTokenValidOrNull()) {
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => waitForValidTokenOrNull().then(resolve), 100)
|
||||
})
|
||||
}
|
||||
|
||||
return waitForValidTokenOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `nhost.graphql.request` to send a GraphQL request. For more serious GraphQL usage we recommend using a GraphQL client such as Apollo Client (https://www.apollographql.com/docs/react).
|
||||
*
|
||||
@@ -70,6 +103,12 @@ export class NhostGraphqlClient {
|
||||
|
||||
const { headers, ...otherOptions } = config || {}
|
||||
const { query, operationName } = resolveRequestDocument(requestOptions.document)
|
||||
|
||||
if (!process.env.TEST_MODE) {
|
||||
// We skip this while running unit tests because the accessToken is generated using faker
|
||||
await this.awaitForValidAccessTokenOrNull()
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(this.httpUrl, {
|
||||
method: 'POST',
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/hasura-auth-js
|
||||
|
||||
## 2.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7baee8a: fix(hasura-auth-js): replace `jwt-decode` with `jose` for decoding access tokens that works on both the browser and Node.js
|
||||
- e0ab6d9: fix: add extra logic to check and wait for a valid JWT
|
||||
|
||||
## 2.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/hasura-auth-js",
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.1",
|
||||
"description": "Hasura-auth client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@@ -66,8 +66,8 @@
|
||||
"dependencies": {
|
||||
"@simplewebauthn/browser": "^6.2.2",
|
||||
"fetch-ponyfill": "^7.1.0",
|
||||
"jose": "^5.2.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"xstate": "^4.38.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import jwt_decode from 'jwt-decode'
|
||||
import * as jose from 'jose'
|
||||
import { interpret } from 'xstate'
|
||||
import {
|
||||
EMAIL_NEEDS_VERIFICATION,
|
||||
@@ -625,7 +625,7 @@ export class HasuraAuthClient {
|
||||
public getDecodedAccessToken(): JWTClaims | null {
|
||||
const jwt = this.getAccessToken()
|
||||
if (!jwt) return null
|
||||
return jwt_decode<JWTClaims>(jwt)
|
||||
return jose.decodeJwt<JWTClaims>(jwt)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -687,9 +687,16 @@ export const createAuthMachine = ({
|
||||
isAutoRefreshDisabled: () => !autoRefreshToken,
|
||||
refreshTimerShouldRefresh: (ctx) => {
|
||||
const { expiresAt } = ctx.accessToken
|
||||
|
||||
if (!expiresAt) {
|
||||
return false
|
||||
}
|
||||
|
||||
// This happens when either the computer goes to sleep or when Chrome descides to suspend the tab
|
||||
if (expiresAt.getTime() < Date.now()) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (ctx.refreshTimer.lastAttempt) {
|
||||
// * If the refresh timer reached the maximum number of attempts, we should not try again
|
||||
if (ctx.refreshTimer.attempts > REFRESH_TOKEN_MAX_ATTEMPTS) {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost/nextjs
|
||||
|
||||
## 2.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.2
|
||||
|
||||
## 2.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@3.2.1
|
||||
|
||||
## 2.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nextjs",
|
||||
"version": "2.1.2",
|
||||
"version": "2.1.4",
|
||||
"description": "Nhost NextJS library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @nhost/nhost-js
|
||||
|
||||
## 3.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2d68fee]
|
||||
- @nhost/graphql-js@0.1.7
|
||||
|
||||
## 3.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7baee8a]
|
||||
- Updated dependencies [e0ab6d9]
|
||||
- @nhost/hasura-auth-js@2.3.1
|
||||
- @nhost/graphql-js@0.1.6
|
||||
|
||||
## 3.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nhost-js",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.7",
|
||||
"description": "Nhost JavaScript SDK",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost/react
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
|
||||
## 3.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.6
|
||||
|
||||
## 3.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.2",
|
||||
"description": "Nhost React library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @nhost/vue
|
||||
|
||||
## 2.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.7
|
||||
|
||||
## 2.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/nhost-js@3.0.6
|
||||
|
||||
## 2.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/vue",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"description": "Nhost Vue library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -1407,6 +1407,9 @@ importers:
|
||||
graphql-ws:
|
||||
specifier: ^5.14.3
|
||||
version: 5.14.3(graphql@16.8.1)
|
||||
jwt-decode:
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2
|
||||
devDependencies:
|
||||
'@apollo/client':
|
||||
specifier: ^3.9.4
|
||||
@@ -1575,6 +1578,9 @@ importers:
|
||||
isomorphic-unfetch:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
jwt-decode:
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2
|
||||
devDependencies:
|
||||
'@nhost/docgen':
|
||||
specifier: workspace:*
|
||||
@@ -1591,12 +1597,12 @@ importers:
|
||||
fetch-ponyfill:
|
||||
specifier: ^7.1.0
|
||||
version: 7.1.0
|
||||
jose:
|
||||
specifier: ^5.2.2
|
||||
version: 5.2.2
|
||||
js-cookie:
|
||||
specifier: ^3.0.5
|
||||
version: 3.0.5
|
||||
jwt-decode:
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2
|
||||
xstate:
|
||||
specifier: ^4.38.3
|
||||
version: 4.38.3
|
||||
@@ -5938,7 +5944,7 @@ packages:
|
||||
/@graphql-tools/utils@8.13.1(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==}
|
||||
peerDependencies:
|
||||
graphql: '>=16.8.1'
|
||||
graphql: 16.8.1
|
||||
dependencies:
|
||||
graphql: 16.8.1
|
||||
tslib: 2.6.2
|
||||
@@ -19441,6 +19447,10 @@ packages:
|
||||
resolution: {integrity: sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==}
|
||||
dev: true
|
||||
|
||||
/jose@5.2.2:
|
||||
resolution: {integrity: sha512-/WByRr4jDcsKlvMd1dRJnPfS1GVO3WuKyaurJ/vvXcOaUQO8rnNObCQMlv/5uCceVQIq5Q4WLF44ohsdiTohdg==}
|
||||
dev: false
|
||||
|
||||
/jpeg-js@0.4.4:
|
||||
resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==}
|
||||
dev: true
|
||||
|
||||
Reference in New Issue
Block a user