Skip to content

Commit

Permalink
Fix/supabase 2.26.0 gotrue warning (#74)
Browse files Browse the repository at this point in the history
* upgrade supabase-js + supabase browser client as singleton

* upgrade minor libs + fix tests

* fix lint and type issues

* fix gh workflow and vitest ui coverage
  • Loading branch information
rphlmr authored Jul 12, 2023
1 parent fcce5a0 commit b9f20bc
Show file tree
Hide file tree
Showing 14 changed files with 58 additions and 62 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ jobs:
with:
useLockFile: false

- name: ⚙️ Build CSS
run: npm run generate:css

- name: 🔬 Lint
run: npm run lint

Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/for-this-stack-repo-only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ jobs:
with:
useLockFile: false

- name: ⚙️ Build CSS
run: npm run generate:css

- name: 🔬 Lint
run: npm run lint

Expand Down
3 changes: 2 additions & 1 deletion app/integrations/i18n/i18next.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ export const i18nextServer = new RemixI18Next({
// The backend you want to use to load the translations
// Tip: You could pass `resources` to the `i18next` configuration and avoid
// a backend here
// @ts-expect-error - `i18next-fs-backend` is not typed
backend: Backend,
});

export async function createI18nextServerInstance(
request: Request,
remixContext: EntryContext
remixContext: EntryContext,
) {
// Create a new instance of i18next so every request will have a
// completely unique instance and not share any state
Expand Down
15 changes: 3 additions & 12 deletions app/integrations/supabase/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,6 @@ function getSupabaseClient(supabaseKey: string, accessToken?: string) {
});
}

/**
* Provides a Supabase Client for the logged in user or get back a public and safe client without admin privileges
*
* It's a per request scoped client to prevent access token leaking over multiple concurrent requests and from different users.
*
* Reason : https://github.com/rphlmr/supa-fly-stack/pull/43#issue-1336412790
*/
function getSupabase(accessToken?: string) {
return getSupabaseClient(SUPABASE_ANON_PUBLIC, accessToken);
}

/**
* Provides a Supabase Admin Client with full admin privileges
*
Expand All @@ -56,4 +45,6 @@ function getSupabaseAdmin() {
return getSupabaseClient(SUPABASE_SERVICE_ROLE);
}

export { getSupabaseAdmin, getSupabase };
const supabaseClient = getSupabaseClient(SUPABASE_ANON_PUBLIC);

export { getSupabaseAdmin, supabaseClient };
4 changes: 3 additions & 1 deletion app/modules/user/service.server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import { db } from "~/database";

import { createUserAccount } from "./service.server";

// @vitest-environment node
// 👋 see https://vitest.dev/guide/environment.html#environments-for-specific-files

// mock db
vitest.mock("~/database", () => ({
db: {
Expand Down Expand Up @@ -113,7 +116,6 @@ describe(createUserAccount.name, () => {
expect(signInRequest.body).toEqual({
email: USER_EMAIL,
password: USER_PASSWORD,
data: {},
gotrue_meta_security: {},
});
expect(fetchAuthAdminUserAPI.size).toEqual(1);
Expand Down
4 changes: 2 additions & 2 deletions app/routes/notes/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { createNote } from "~/modules/note";
import { assertIsPost, isFormProcessing } from "~/utils";

export const NewNoteFormSchema = z.object({
title: z.string().min(2, "require-title"),
title: z.string().min(1, "require-title"),
body: z.string().min(1, "require-body"),
});

Expand All @@ -31,7 +31,7 @@ export async function action({ request }: LoaderArgs) {
headers: {
"Set-Cookie": await commitAuthSession(request, { authSession }),
},
}
},
);
}

Expand Down
9 changes: 4 additions & 5 deletions app/routes/oauth.callback.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useEffect, useMemo } from "react";
import { useEffect } from "react";

import { json, redirect } from "@remix-run/node";
import type { LoaderArgs, ActionArgs } from "@remix-run/node";
import { useActionData, useFetcher, useSearchParams } from "@remix-run/react";
import { parseFormAny } from "react-zorm";
import { z } from "zod";

import { getSupabase } from "~/integrations/supabase";
import { supabaseClient } from "~/integrations/supabase";
import {
refreshAccessToken,
commitAuthSession,
Expand Down Expand Up @@ -98,12 +98,11 @@ export default function LoginCallback() {
const fetcher = useFetcher();
const [searchParams] = useSearchParams();
const redirectTo = searchParams.get("redirectTo") ?? "/notes";
const supabase = useMemo(() => getSupabase(), []);

useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((event, supabaseSession) => {
} = supabaseClient.auth.onAuthStateChange((event, supabaseSession) => {
if (event === "SIGNED_IN") {
// supabase sdk has ability to read url fragment that contains your token after third party provider redirects you here
// this fragment url looks like https://.....#access_token=evxxxxxxxx&refresh_token=xxxxxx, and it's not readable server-side (Oauth security)
Expand All @@ -129,7 +128,7 @@ export default function LoginCallback() {
// prevent memory leak. Listener stays alive 👨‍🎤
subscription.unsubscribe();
};
}, [fetcher, redirectTo, supabase.auth]);
}, [fetcher, redirectTo]);

return error ? <div>{error.message}</div> : null;
}
9 changes: 4 additions & 5 deletions app/routes/reset-password.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useEffect, useState } from "react";

import type { ActionArgs, LoaderArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
Expand All @@ -8,7 +8,7 @@ import { parseFormAny, useZorm } from "react-zorm";
import { z } from "zod";

import { i18nextServer } from "~/integrations/i18n";
import { getSupabase } from "~/integrations/supabase";
import { supabaseClient } from "~/integrations/supabase";
import {
commitAuthSession,
getAuthSession,
Expand Down Expand Up @@ -104,12 +104,11 @@ export default function ResetPassword() {
const actionData = useActionData<typeof action>();
const transition = useTransition();
const disabled = isFormProcessing(transition.state);
const supabase = useMemo(() => getSupabase(), []);

useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((event, supabaseSession) => {
} = supabaseClient.auth.onAuthStateChange((event, supabaseSession) => {
// In local development, we doesn't see "PASSWORD_RECOVERY" event because:
// Effect run twice and break listener chain
if (event === "PASSWORD_RECOVERY" || event === "SIGNED_IN") {
Expand All @@ -125,7 +124,7 @@ export default function ResetPassword() {
// prevent memory leak. Listener stays alive 👨‍🎤
subscription.unsubscribe();
};
}, [supabase.auth]);
}, []);

return (
<div className="flex min-h-full flex-col justify-center">
Expand Down
11 changes: 7 additions & 4 deletions app/utils/http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
safeRedirect,
} from "./http.server";

// @vitest-environment node
// 👋 see https://vitest.dev/guide/environment.html#environments-for-specific-files

const BASE_URL = "https://my-app.com";

describe(getCurrentPath.name, () => {
Expand All @@ -19,7 +22,7 @@ describe(getCurrentPath.name, () => {
describe(makeRedirectToFromHere.name, () => {
it("should return search params with redirectTo set with current request url path", () => {
expect(makeRedirectToFromHere(new Request(`${BASE_URL}/profile`))).toEqual(
new URLSearchParams([["redirectTo", "/profile"]])
new URLSearchParams([["redirectTo", "/profile"]]),
);
});
});
Expand All @@ -31,13 +34,13 @@ describe(getRedirectTo.name, () => {

it("should return url redirectTo param value", () => {
expect(getRedirectTo(new Request(`${BASE_URL}?redirectTo=/profile`))).toBe(
"/profile"
"/profile",
);
});

it("should return root redirectTo param value if invalid param value", () => {
expect(getRedirectTo(new Request(`${BASE_URL}?redirectTo=//profile`))).toBe(
"/"
"/",
);
});
});
Expand Down Expand Up @@ -75,7 +78,7 @@ describe(notFound.name, () => {

it("should return message", async () => {
expect(await notFound("not-found-message").text()).toBe(
"not-found-message"
"not-found-message",
);
});
});
Expand Down
4 changes: 3 additions & 1 deletion cypress/support/delete-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ async function deleteUser(email: string) {
}
}

await deleteAuthAccount(user?.id!);
if (user?.id) {
await deleteAuthAccount(user.id);
}
}

deleteUser(process.argv[2]);
2 changes: 1 addition & 1 deletion cypress/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"compilerOptions": {
"baseUrl": ".",
"noEmit": true,
"types": ["node", "cypress", "@testing-library/cypress"],
"types": ["node"],
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
Expand Down
45 changes: 22 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@remix-run/node": "*",
"@remix-run/react": "*",
"@remix-run/serve": "*",
"@supabase/supabase-js": "^2.24.0",
"@supabase/supabase-js": "^2.26.0",
"cookie": "^0.5.0",
"i18next": "^21.9.1",
"i18next-browser-languagedetector": "^6.1.5",
Expand All @@ -42,46 +42,45 @@
"react-i18next": "^11.18.5",
"react-zorm": "^0.6.1",
"remix-i18next": "^4.1.1",
"tailwind-merge": "^1.10.0",
"zod": "^3.19.1"
"tailwind-merge": "^1.13.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@faker-js/faker": "^7.6.0",
"@faker-js/faker": "^8.0.2",
"@remix-run/dev": "*",
"@remix-run/eslint-config": "*",
"@remix-run/eslint-config": "1.18.1",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.9",
"@testing-library/cypress": "^8.0.3",
"@testing-library/cypress": "^9.0.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/i18next-fs-backend": "^1.1.2",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^3.1.0",
"@vitest/coverage-c8": "^0.28.5",
"@vitest/coverage-v8": "^0.33.0",
"cross-env": "^7.0.3",
"cypress": "^10.10.0",
"cypress": "^12.17.1",
"dotenv-cli": "^7.0.0",
"eslint": "^8.34.0",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-tailwindcss": "^3.9.0",
"happy-dom": "^7.6.0",
"msw": "^0.49.0",
"eslint-plugin-tailwindcss": "^3.13.0",
"happy-dom": "^10.1.1",
"msw": "^1.2.2",
"npm-run-all": "^4.1.5",
"prettier": "2.8.4",
"prettier-plugin-tailwindcss": "^0.2.3",
"prettier": "3.0.0",
"prettier-plugin-tailwindcss": "^0.4.0",
"prisma": "^4.10.1",
"start-server-and-test": "^1.14.0",
"tailwind-scrollbar": "^2.1.0",
"tailwindcss": "^3.2.7",
"start-server-and-test": "^2.0.0",
"tailwind-scrollbar": "^3.0.4",
"tailwindcss": "^3.3.2",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.2",
"typescript": "^4.9.5",
"vite-tsconfig-paths": "^4.0.5",
"vitest": "^0.28.5"
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.6",
"vite-tsconfig-paths": "^4.2.0",
"vitest": "^0.33.0"
},
"engines": {
"node": ">=16"
Expand Down
1 change: 0 additions & 1 deletion tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ module.exports = {
require("@tailwindcss/typography"),
require("@tailwindcss/forms"),
require("@tailwindcss/aspect-ratio"),
require("@tailwindcss/line-clamp"),
require("tailwind-scrollbar"),
],
};
7 changes: 7 additions & 0 deletions test/setup-test-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ process.env.SUPABASE_ANON_PUBLIC = "{ANON_PUBLIC}";
process.env.SUPABASE_URL = "https://supabase-project.supabase.co";
process.env.SERVER_URL = "http://localhost:3000";


if(typeof window !== 'undefined'){
// @ts-expect-error missing vitest type
window.happyDOM.settings.enableFileSystemHttpRequests = true;
}


installGlobals();

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
Expand Down

0 comments on commit b9f20bc

Please sign in to comment.