Code Monkey home page Code Monkey logo

Comments (10)

perfectbase avatar perfectbase commented on June 26, 2024

Hi @yousihy!

I just tested it here with a similar setup, but I couldn't replicate the problem.
I believe the configuration is correct.

Some things you could try to narrow the problem down:

  • reload the page a few times (this will make sure that the initial load happens after the cookie is already set)
  • take a look at your network tab to see if the init request is succeeding
  • put some logs in the createContext, so you know exactly what's being set
  • try calling the reset function before showing the images
const { edgestore, reset } = useEdgeStore();

async function runAfterAuthChange() {
  await reset(); // this will re-run the createContext function
}

Other thing.. There was is a bug for accessControl in production environments (with https) in the current version. It's unrelated to this problem, but you might want to update your package.json to:

"@edgestore/react": "^0.1.5-alpha.5",
"@edgestore/server": "^0.1.5-alpha.5",

this should become stable soon.

Let me know if this helps you solve the problem

from edgestore.

yousihy avatar yousihy commented on June 26, 2024

Thanks for the prompt response.

Ok, so here is what I did:

Since I am using Clerk, I don't know how to trigger the reset after SignIn. So I added this logic inside useEffect in the page I am using.

The first image worked and loaded successfully after uploading. However, other images are not loading with the same unauthorized error. I am using the same component on the Edgestore website for multiple image upload, but I removed the progress bars and replaced them with a logic to display the images that were uploaded.

I deleted the cookie manually and I can see it is being generated again.

I can see that the init request is getting 200.

The logs in the createContext are clearly showing that the UserId is being returned fine with every request.

I did update the libraries in the package, but it had no effect.

For the sake of moving forward with my project, I will ignore the accessControl for now. However, I am unable to delete the Bucket from the Edgestore now that it is protected and I don't want to create a new Bucket. How to do that?

from edgestore.

perfectbase avatar perfectbase commented on June 26, 2024

@yousihy I just created a simple example app with access control in a way that only signed in users can see the images.

Screen.Recording.2023-12-01.at.17.34.44.mov

Here is the router configuration:

import { initEdgeStore } from '@edgestore/server';
import {
  createEdgeStoreNextHandler,
  type CreateContextOptions,
} from '@edgestore/server/adapters/next/app';
import { initEdgeStoreClient } from '@edgestore/server/core';
import { cookies } from 'next/headers';
import { z } from 'zod';

type Context = {
  signedIn: 'true' | 'false';
};

function createContext(_opts: CreateContextOptions): Context {
  const signedIn = cookies().get('signedIn')?.value ?? 'false';
  return {
    signedIn: signedIn === 'true' ? 'true' : 'false',
  };
}

const es = initEdgeStore.context<Context>().create();

/**
 * This is the main router for the Edge Store buckets.
 */
const edgeStoreRouter = es.router({
  privateFiles: es
    .fileBucket({
      accept: ['image/*'],
    })
    .input(z.object({ type: z.enum(['post', 'article']) }))
    .path(({ input }) => [{ type: input.type }])
    .accessControl({
      signedIn: { not: 'false' },
    }),
});

const handler = createEdgeStoreNextHandler({
  router: edgeStoreRouter,
  createContext,
});

export { handler as GET, handler as POST };

/**
 * This type is used to create the type-safe client for the frontend.
 */
export type EdgeStoreRouter = typeof edgeStoreRouter;

export const backendClient = initEdgeStoreClient({
  router: edgeStoreRouter,
  baseUrl: 'http://localhost:3000/api/edgestore',
});

You can run this example in your machine with the following steps:

  • clone the repo
  • checkout to the next branch
  • cd into the examples/basic-access-control folder
  • add your environment variables to .env.local
  • npm install
  • npm run dev
  • access it in http://localhost:3000

I am unable to delete the Bucket from the Edgestore now that it is protected and I don't want to create a new Bucket. How to do that?

Sorry. This is a missing feature in the dashboard. It will be added eventually, but right now all you can do is ignore the old bucket or delete and recreate the whole project.

from edgestore.

yousihy avatar yousihy commented on June 26, 2024

Hey! thanks for the updated code. I tried your code after changing the auth logic to use Clerk and instead of using fileBucket, I used the imageBucket.

I first tried to upload 1 image. And it worked. I was able to see the image. Then I tried uploading two images, both are getting 500. I am not sure why it is working for the first image but not for subsequent images:

image

After this, ALL image uploads are getting the 500. I tried to reload the app, restart the server, clear the cashe ... nothing worked.

HOWEVER! By mere luck! I looked at the code and I decided to try loading the images using the url and not the thumbnailUrl, and it worked! :)

<MultiFileDropzoneSimple
                      loadingImages={isUploading}
                      value={fileStates}
                      onChange={(files) => {
                        setFileStates(files)
                      }}
                      onFilesAdded={async (addedFiles) => {
                        setFileStates([...fileStates, ...addedFiles])
                        setIsUploading(true)
                        await Promise.all(
                          addedFiles.map(async (addedFileState) => {
                            try {
                              const res =
                                await edgestore.privateFilesTest.upload({
                                  file: addedFileState.file,
                                  options: {
                                    temporary: true,
                                  },
                                  input: { type: "unit" },
                                  onProgressChange: async (progress) => {
                                    updateFileProgress(
                                      addedFileState.key,
                                      progress
                                    )
                                    if (progress === 100) {
                                      await new Promise((resolve) =>
                                        setTimeout(resolve, 1000)
                                      )
                                      updateFileProgress(
                                        addedFileState.key,
                                        "COMPLETE"
                                      )
                                    }
                                  },
                                })
                              setUploadedFiles((uploadedFiles) => [
                                ...uploadedFiles,
                                {
                                  url: res.url,
                                  thumbnailUrl: res.thumbnailUrl,
                                },
                              ])
                            } catch (err) {
                              updateFileProgress(addedFileState.key, "ERROR")
                            }
                          })
                        )
                        setIsUploading(false)
                      }}
                    />
                  </div>
                  {uploadedFiles.length > 0 && (
                    <div className="grid grid-cols-4 mt-5 gap-2">
                      {uploadedFiles.map((file) => (
                        <div
                          key={file.thumbnailUrl || file.url}
                          className="relative w-full h-40 bg-gray-100 rounded-md overflow-hidden"
                        >
                          <img
                            src={file.thumbnailUrl || file.url}
                            className="absolute inset-0 w-full h-full object-cover"
                          />
                        </div>
                      ))}
                    </div>
                  )}

I update the below section to use url instead:

 setUploadedFiles((uploadedFiles) => [
                                ...uploadedFiles,
                                {
                                  url: res.url,
                                  thumbnailUrl: res.url,
                                },
                              ])

And everything is working now:

image

Am I doing something wrong when it comes to setting or reading the thumbnailUrl?

from edgestore.

wadahkode avatar wadahkode commented on June 26, 2024

POST http://localhost:3000/api/edgestore/init 500 (Internal Server Error)

Saya baru saja mengikuti tutorial dari dokumentasi secara langsung, tapi saya sudah mendapat pesan error ini, dan berikut konfigurasi yang baru saya tulis :

...
type Context = {
  userId: string | null | undefined;
};

async function createContext({ req }: CreateContextOptions): Promise<Context> {
  // const { id, role } = await getUserSession(req); // replace with your own session logic
  const session = await getServerSession(authOptions);

  if (session) {
    return {
      userId: session?.user?.name,
    };
  }

  return {
    // userId: "", // ternyata tidak boleh kosong
    userId: "123"
  };
}
...

from edgestore.

yousihy avatar yousihy commented on June 26, 2024

POST http://localhost:3000/api/edgestore/init 500 (Internal Server Error)

Saya baru saja mengikuti tutorial dari dokumentasi secara langsung, tapi saya sudah mendapat pesan error ini, dan berikut konfigurasi yang baru saya tulis :

...
type Context = {
  userId: string | null | undefined;
};

async function createContext({ req }: CreateContextOptions): Promise<Context> {
  // const { id, role } = await getUserSession(req); // replace with your own session logic
  const session = await getServerSession(authOptions);

  if (session) {
    return {
      userId: session?.user?.name,
    };
  }

  return {
    // userId: "", // ternyata tidak boleh kosong
    userId: "123"
  };
}
...

Shouldn't you reply in English so everyone can understand what you're saying? :)

from edgestore.

perfectbase avatar perfectbase commented on June 26, 2024

@wadahkode If you need support running edgestore that's unrelated to this issue, please create a new issue or ask in the Discord server! 🙏
I'll do my best to help you out.

from edgestore.

perfectbase avatar perfectbase commented on June 26, 2024

@yousihy

HOWEVER! By mere luck! I looked at the code and I decided to try loading the images using the url and not the thumbnailUrl, and it worked! :)

Interesting! I'll investigate as soon as I can.

Some things to be aware of when using thumbnails (probably unrelated to the problem):

  • Thumbnails are only created for image buckets.
  • Thumbnails are not always created. They are created only for images larger than a certain size.
  • Thumbnails may take a few seconds to be created after the upload finishes, so if you try to use it as soon as the upload ends, it might still be unaccessible.

That said... I haven't tried using thumbnails with a protected image bucket, there might be a bug in there. I'll let you know when I take a look.

from edgestore.

perfectbase avatar perfectbase commented on June 26, 2024

@yousihy I changed my example project to use image buckets with the thumbnailUrls and I couldn't replicate the problem.
I temporarily deployed the sample app here: https://example-access-control.vercel.app/
the code is updated in the next branch inside examples/basic-access-control.
Take a look to see if you can find the problem.

Also, another issue with protected files was reported by a user in Discord.
It's unrelated to this issue, but I'll share it here as well:

It seems that protected files are not accessible in some browsers in a deployed production environment.
Here are some browsers I tested:

  • Desktop(Mac) Chrome: OK
  • Desktop(Mac) Arc: OK
  • Desktop(Mac) Firefox: OK
  • Desktop(Mac) Safari: NG
  • Mobile(iOS) Chrome: NG
  • Mobile(iOS) Safari: NG

This is happens because some browsers have third party cookies disabled by default.
You can make it work by enabling third party cookies for the browser.
But this workaround is not realistic as we can't ask all our users to change their configuration.

Another temporary workaround would be to use the proxyUrl that is used in development to show the file. Considering that the files are not too big, this can be a good workaround for now, as they will be proxied through your api which is in the same domain as the site.

/**
 * @example
 * const url = 'https://files.edgestore.dev/some/file/path.txt';
 * const proxyUrl = convertToProxyUrl(url);
 * // => 'https://my-site-domain.com/api/edgestore/proxy-file?url=https%3A%2F%2Ffiles.edgestore.dev%2Fsome%2Ffile%2Fpath.txt'
 */
function convertToProxyUrl(url: string) {
  const apiPath = '/api/edgestore'
  if (process.env.NODE_ENV === 'production' && !url.includes('/_public/')) {
    // In development this is already done internally
    const proxyUrl = new URL(window.location.origin);
    proxyUrl.pathname = `${apiPath}/proxy-file`;
    proxyUrl.search = new URLSearchParams({
      url,
    }).toString();
    return proxyUrl.toString();
  }
  return url;
}

I believe this issue can only be completely handled when I make a feature for setting custom domains for the file storage.
I'll try to prioritize this after the current release I'm working on right now.
(custom domains will probably be a PRO feature)

from edgestore.

perfectbase avatar perfectbase commented on June 26, 2024

I'll close this issue for now.
If you have any other problems feel free to let me know.

from edgestore.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.