nuxt-hub / core

Build full-stack applications with Nuxt on CloudFlare, with zero configuration.
https://hub.nuxt.com
Apache License 2.0
910 stars 50 forks source link

Question: is it possible to set compatibility_flags for wrangler.toml? #246

Open remihuigen opened 2 weeks ago

remihuigen commented 2 weeks ago

I ran into this error: [unenv] crypto.createHmac is not implemented yet! using the algolia client client.generateSecuredApiKey() method.

Hmac should be available in workers if the nodejs_compat flag is set in wranger.toml, but I don't see a way to do this.

Adding a wrangler.toml file to the root of my directory does nothing.

any suggestions on how to accomplish this? Thanks!

atinux commented 2 weeks ago

Hey @remihuigen

When deploying with the @nuxthub/core module, the nodejs_compat flag is set automatically for you.

You can see it in your Cloudflare Pages project: CleanShot 2024-08-28 at 11 51 30@2x

Could you verify?

remihuigen commented 2 weeks ago

@atinux You are correct the flag is set indeed...

Any other advice on how to resolve this issue? My guess is that this line of code is the culprit.

unenv should support the usage of crypto in workers: https://github.com/unjs/unenv?tab=readme-ov-file#cloudflare

atinux commented 2 weeks ago

I am wondering if Algolia SDK should not import from node:crypto though πŸ€”

pi0 commented 2 weeks ago

If you can enable compatibility flags for hub users, a quick way would be to use node:crypto import as an external (just like how node:async_context is handled today).

We can't do this automatically for Nitro users but working on a hybrid approach coming soon with unenv v2 / nitro v3 that fixes the issue.

Otherwise indeed we have to kindly ask upstream libraries to explicitly avoid Node-speicific features.

atinux commented 2 weeks ago

Opened https://github.com/algolia/api-clients-automation/pull/3608, let's see if this will fix!

atinux commented 1 week ago

Could you try the latest version of the algolia client @remihuigen ?

remihuigen commented 1 week ago

okay, upgraded to 5.2.3 (was still using v4 previously).

My endpoint now returns a different 500 error

{
    "message": "c.generateSecuredApiKey is not a function",
    "statusCode": 500
}

It's a bit hard to trace the issue, since I have no way to simulate a CF pages env locally, and in a regular dev env everything works just fine

npx wrangler pages dev dist/ throws error about missing bindings. nuxt preview throws error Cannot find nitro.json

for context

basically, what I'm trying to achieve is that my endpoint /api/search/config returns a securedApiKey (among other things)

// api/search/config.get.ts

export default defineEventHandler({
  onRequest: [accessControlSearch],
  handler: async (event) => {
    const { refresh } = getQuery(event)

    const { appId, privateKey } = useRuntimeConfig().algoliaSearch.onderwijsloket
    const { session } = event.context
    const indices = await getOwlIndices()

    // Secured api key for user
    // https://www.algolia.com/doc/api-reference/api-methods/generate-secured-api-key/#method-param-usertoken
    const algolia = useSearch({session})
    const {algoliaSecuredKeyStorage} = usePrefixedStorage()

    if (refresh === 'true' || refresh === "1") {
      await algoliaSecuredKeyStorage.removeItem(session.itemId)
    } 

    let securedKey: AlgoliaSecuredKey | null = await algoliaSecuredKeyStorage.getItem(session.itemId)
    // If in cache
    if (securedKey) {
      // Check if key is still valid
      if (securedKey.apiKeyValidUntil > new Date().getTime()) {
        return {
          applicationId: appId,
          apiKey: securedKey.apiKey,
          apiKeyValidUntil: securedKey.apiKeyValidUntil,
          indices
        }
      } else {
        // Remove it from storage
        await algoliaSecuredKeyStorage.removeItem(session.itemId)
      }
    } 

    const algolia = useSearch({session})
    const validUntil = addDaysToDate(new Date(), 365).getTime()

    const restrictions = {
      userToken: session.itemId,
      validUntil,
      restrictIndices: indices
    }

    const generatedSecuredKey: string = algolia.generateSecuredApiKey(
        {parentApiKey: privateKey, restrictions}
    )

    await algoliaSecuredKeyStorage.setItem(session.itemId, {
      apiKey: generatedSecuredKey,
      apiKeyValidUntil: validUntil
    })

    return {
      applicationId: appId,
      apiKey: generatedSecuredKey,
      apiKeyValidUntil: validUntil,
      indices
    }
  }
})

the useSearch utility return the algolia client (as per https://www.algolia.com/doc/libraries/javascript/v5/)

atinux commented 1 week ago

I know the debugging experience right now is not best, could you check https://hub.nuxt.com/docs/recipes/debug ?

remihuigen commented 1 week ago

Did some more digging. Found a couple of issues. First: my implementation of V5 was incorrect.

After I fixed that I encountered a new error XMLHttpRequest is not defined

Apparently, the browser build from the algolia client is used in bundling in stead of the node build. Haven't figured out why though

From .wrangler/tmp/chunks/_/algolia.mjs πŸ‘‡

function algoliasearch(appId, apiKey, options) {
    function initRecommend(initOptions = {}) {
        return recommendClient(initOptions.appId || appId, initOptions.apiKey || apiKey, initOptions.options);
    }
    function initAnalytics(initOptions = {}) {
        return analyticsClient(initOptions.appId || appId, initOptions.apiKey || apiKey, initOptions.region, initOptions.options);
    }
    function initAbtesting(initOptions = {}) {
        return abtestingClient(initOptions.appId || appId, initOptions.apiKey || apiKey, initOptions.region, initOptions.options);
    }
    function initPersonalization(initOptions) {
        return personalizationClient(initOptions.appId || appId, initOptions.apiKey || apiKey, initOptions.region, initOptions.options);
    }
    return {
        ...searchClient(appId, apiKey, {
            timeouts: {
                connect: DEFAULT_CONNECT_TIMEOUT_BROWSER$3,
                read: DEFAULT_READ_TIMEOUT_BROWSER$3,
                write: DEFAULT_WRITE_TIMEOUT_BROWSER$3,
            },
            requester: createXhrRequester(),
            algoliaAgents: [{ segment: 'Browser' }],
            authMode: 'WithinQueryParameters',
            responsesCache: createMemoryCache$3(),
            requestsCache: createMemoryCache$3({ serializable: false }),
            hostsCache: createFallbackableCache$3({
                caches: [createBrowserLocalStorageCache$3({ key: `${apiClientVersion}-${appId}` }), createMemoryCache$3()],
            }),
            ...options,
        }),
        /**
         * Get the value of the `algoliaAgent`, used by our libraries internally and telemetry system.
         */
        get _ua() {
            return this.transporter.algoliaAgent.value;
        },
        initAbtesting,
        initAnalytics,
        initPersonalization,
        initRecommend,
    };
}
atinux commented 1 week ago

Would you mind creating an issue there? Maybe they have some hints about it

remihuigen commented 1 week ago

Sure algolia/algoliasearch-client-javascript#1548

remihuigen commented 3 days ago

Well, I'm back to where I started, which is [unenv] crypto.createHmac is not implemented yet!

With 5.4.0, the algolia client now resolves correctly to the node build. But it also reintroduced the issue with the crypto package. Which is weird, since this was resolved in 5.2.2 with the node: prefix in crypto import

atinux commented 3 days ago

Let's try something:

export default defineNuxtConfig({
  hub: {
    bindings: {
      compatibilityFlags: ['nodejs_compat_v2']
    }
  },
  nitro: {
    unenv: {
      external: ['node:crypto']
    }
  }
})

Will use use the node compat which is up to 89,9% β€” https://workers-nodejs-compat-matrix.pages.dev/

remihuigen commented 3 days ago
✘ [ERROR] service core:user:worker: Uncaught Error: No such module "node:crypto".

    imported from "3rm0k1wwdzm.js"

✘ [ERROR] MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.

with @nuxthub/core@0.7.9 and wrangler@3.73.0

remihuigen commented 3 days ago

Got this error locally (similar to https://github.com/nuxt-hub/core/issues/273). Just did a deploy, which failed after building worker chunks with

✘ [ERROR] The `nodejs_compat_v2` compatibility flag is experimental and must be prefixed with `experimental:`. Use `experimental:nodejs_compat_v2` flag instead.

updated config to

  hub: {
    analytics: true,
    cache: true,
    blob: false,
    database: true,
    kv: true,
    ai: true,
    bindings: {
      compatibilityFlags: ['experimental:nodejs_compat_v2']
    }
  }

which failed with

13:59:36.259 [error] [nuxt:hub] Invalid hub config
13:59:36.423 Failed: Error while executing user command. Exited with error code: 1
13:59:36.433 Failed: build command exited with code: 1
13:59:37.733 Failed: error occurred while running build command
9M6 commented 4 hours ago

Same thing happened to me, did you find a solution @remihuigen ?

9M6 commented 4 hours ago

Also setting compatibilityFlags: ['nodejs_compat_v2'] programatically in nuxt.config doesnt really work, I need to do it manually from cloudflare.

remihuigen commented 4 hours ago

Same thing happened to me, did you find a solution @remihuigen ?

Not yet. Upgrading the client to ^5.4.0 did resolve some worker runtime issues it had, but not this one.

9M6 commented 4 hours ago

It seems to be a cloudflare issue, they say to create a new app 🀦 or manually deploy with wrangler

https://community.cloudflare.com/t/pages-app-in-permanently-broken-state-due-to-wrangler-toml/708610/7 (not the same problem as not being able to run nodejs_compat_v2, I tried with a new app, did not work)

atinux commented 3 hours ago

Let me check this, they changed it without notice…

9M6 commented 3 hours ago

nodejs_compat_v2 ->

✘ [ERROR] The `nodejs_compat_v2` compatibility flag is experimental and must be prefixed with `experimental:`. Use `experimental:nodejs_compat_v2` flag instead.

experimental:nodejs_compat_v2 ->

13:14:29.179 | Error: Failed to publish your Function. Got error: No such compatibility flag: experimental:nodejs_compat_v2
atinux commented 3 hours ago

I just deployed with nuxthub deploy with

export default defineNuxtConfig({
  modules: ['@nuxthub/core'],
  hub: {
    bindings: {
      compatibilityFlags: ['nodejs_compat_v2']
    }
  },
})

and it works:

CleanShot 2024-09-14 at 12.22.41@2x.png
9M6 commented 3 hours ago

@atinux is this though nuxthub or deployed through github? also what might affect nodejs_compact_v2 ? any special configurations?

9M6 commented 2 hours ago

Also just deployed on a new and clean cloudflare pages app, and got the same error:

13:40:24.237 | ✘ [ERROR] The `nodejs_compat_v2` compatibility flag is experimental and must be prefixed with `experimental:`. Use `experimental:nodejs_compat_v2` flag instead.

Do I need to setup some account-wide config? Is maybe a build cache problem? maybe the bindings are creating the issue?

9M6 commented 2 hours ago

I tried also with another app that I have not used/deployed for 3 months, this one is nuxt too, and its throwing the same error.

atinux commented 2 hours ago

You have to use nuxthub deploy or deploy using admin.hub.nuxt.com to work

9M6 commented 2 hours ago

@atinux seems to be a general problem where a subset of users are having this issue CleanShot 2024-09-14 at 13 52 29@2x

9M6 commented 2 hours ago

I guess, I'll wait for when it becomes GA on the 23rd.