Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
remihuigen opened this issue Aug 28, 2024 · 40 comments
Open
Labels
question Further information is requested

Comments

@remihuigen
Copy link

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
Copy link
Contributor

atinux commented Aug 28, 2024

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?

@atinux atinux added the question Further information is requested label Aug 28, 2024
@remihuigen
Copy link
Author

@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

Copy link
Contributor

atinux commented Aug 28, 2024

I am wondering if Algolia SDK should not import from node:crypto though 🤔

@pi0
Copy link

pi0 commented Aug 28, 2024

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
Copy link
Contributor

atinux commented Aug 28, 2024

Opened algolia/api-clients-automation#3608, let's see if this will fix!

@atinux
Copy link
Contributor

atinux commented Sep 1, 2024

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

@remihuigen
Copy link
Author

remihuigen commented Sep 2, 2024

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
Copy link
Contributor

atinux commented Sep 2, 2024

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

@remihuigen
Copy link
Author

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,
    };
}

Copy link
Contributor

atinux commented Sep 5, 2024

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

@remihuigen
Copy link
Author

@remihuigen
Copy link
Author

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

Copy link
Contributor

atinux commented Sep 11, 2024

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
Copy link
Author

✘ [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/[email protected] and [email protected]

@remihuigen
Copy link
Author

Got this error locally (similar to #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
Copy link

9M6 commented Sep 14, 2024

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

@9M6
Copy link

9M6 commented Sep 14, 2024

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

@remihuigen
Copy link
Author

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
Copy link

9M6 commented Sep 14, 2024

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)

Copy link
Contributor

atinux commented Sep 14, 2024

Let me check this, they changed it without notice…

@9M6
Copy link

9M6 commented Sep 14, 2024

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

Copy link
Contributor

atinux commented Sep 14, 2024

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
Copy link

9M6 commented Sep 14, 2024

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

@9M6
Copy link

9M6 commented Sep 14, 2024

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
Copy link

9M6 commented Sep 14, 2024

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.

Copy link
Contributor

atinux commented Sep 14, 2024

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

@9M6
Copy link

9M6 commented Sep 14, 2024

@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
Copy link

9M6 commented Sep 14, 2024

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

Copy link
Contributor

atinux commented Sep 14, 2024

Damn, this is an issue in Cloudflare indeed, works only with nuxthub deploy for now 😄

@remihuigen
Copy link
Author

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/

Just came around to trying this, since we can now deploy with nodejs_compat_v2. But I'm still getting "[unenv] crypto.createHmac is not implemented yet!"

I'm now running into similar issues with the cloudinary node SDK.

this one returns Cannot read properties of undefined (reading 'node') when using nitro.unenv.external = ['node:crypto']

Copy link
Contributor

atinux commented Sep 29, 2024

Could you please try by removing the hub.bindings.compatibilityFlags and deploy again?

@remihuigen
Copy link
Author

same thing unfortunately...

"[unenv] crypto.createHmac is not implemented yet!"

@RakuThe1
Copy link

same thing unfortunately...

"[unenv] crypto.createHmac is not implemented yet!"

Did you find a solution @remihuigen ? Having same issue

@remihuigen
Copy link
Author

@RakuThe1 unfortunately not

@atinux
Copy link
Contributor

atinux commented Oct 21, 2024

Please make sure to do this in your nuxt.config.ts, make sure to use latest @nuxthub/core and redeploy:

export default defineNuxtConfig({
  // ...
  hub: {
    // ...
    bindings: {
      compatibilityDate: '2024-10-21'
    }
  },
})

@remihuigen
Copy link
Author

@atinux added the compatibilityDate to hub.bindings, but the issue persists.

Upgrading @nuxthub/core from 0.7.20 to 0.7.34 also seems to break caching for some reason (for both functions and handlers)

Copy link
Contributor

atinux commented Oct 22, 2024

What is the error you have regarding caching?

@remihuigen
Copy link
Author

No errors are logged, but requests are no longer cached. Just rolled back to previous deploy (with core 0.7.20) and caching resumed.

The actual code didnt change between the two deploys, i only updated their core package and set the compatibility date as per your suggestion.

Haven't had the time yet to trace the cause though. Glanced over the changelog, but didn't see anything between 0.7.20 and 0.7.34 that was a clear cause. Any pointers as to what the issue might be?

Copy link
Contributor

atinux commented Oct 22, 2024

Actually the cache entries not use expiration ttl. What are you cache options? Do you use swr and what is the max age?

@remihuigen
Copy link
Author

I'm only caching server api handlers and function (mostly functions). MaxAge is one day for most functions, but varies. Haven't used swr anywhere.

For example

const getEvents = defineCachedFunction(async (options: StatsQueryOptions) => {
    // Run fetch request and return results
}, {
    maxAge: 60 * 60 * 24 * 1,
    name: 'onderwijsloketScheduledEvents'
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants