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

Notion sdk package compatibility #235

Open
mathieucollet opened this issue Aug 21, 2024 · 13 comments
Open

Notion sdk package compatibility #235

mathieucollet opened this issue Aug 21, 2024 · 13 comments
Labels
edge-compatibility Something is not yet edge-compatible? question Further information is requested

Comments

@mathieucollet
Copy link

Is your feature request related to a problem? Please describe.
The error may be mine, but I think the js package Notion-sdk-js is not compatible with deployment via NuxtHub. Here's my little request, I don't realize how much work it would take, but nothing ventured, nothing gained.

Describe the solution you'd like
I mean, juste having the package working would be great 👍🏼

Describe alternatives you've considered
Doing requests to the Notion API without the use of the package.

Additional context
Here is the simplified code for server/api and the component using it. Code that, just for the record, works when running the dev version locally, but doesn't work in production or via wrangler.

// /server/api/database.get.ts
import {Client, collectPaginatedAPI} from "@notionhq/client"

const { notionApiToken, databaseId} = useRuntimeConfig()
const notion = new Client({
    auth: notionApiToken
})
const getData = async () => await collectPaginatedAPI(notion.databases.query, {
    database_id: databaseId,
    page_size: 100
})
export default defineEventHandler(() => getData())
<!--/components/Dashboard.vue-->
<template>
  <div>
    <p v-if="status === 'pending'">Loading....</p>
    <div v-else>{{ data }}</div>
  </div>
</template>

<script setup lang="ts">
const {status, data} = await useLazyFetch("/api/database")
watch(data, (newData) => {})
</script>

Thanks for reading

@atinux atinux added question Further information is requested edge-compatibility Something is not yet edge-compatible? labels Aug 21, 2024
@atinux
Copy link
Contributor

atinux commented Aug 21, 2024

Hey @mathieucollet

Happy to read https://hub.nuxt.com/docs/recipes/debug and give investigate about what can cause such issue?

@mathieucollet
Copy link
Author

mathieucollet commented Aug 21, 2024

I had the logs ready and forgot to add them to my request, sorry...

✘ [ERROR] [nuxt] [request error] [unhandled] [500] Cannot read properties of undefined (reading 'call')

    at Client.request
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/_/index.mjs:958:131)
    at Object.query
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/_/index.mjs:719:29)
    at Object.handler
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/routes/api/database.get.mjs:10:39)
    at null.<anonymous>
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5108:43)
    at async Object.handler
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5177:19)
    at async toNodeHandle
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5447:7)
    at async ufetch
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5820:17)
    at async $fetchRaw2
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5693:26)
    at async $fetch22
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5739:15)
  [nuxt] [request error] [unhandled] [500] Cannot read properties of undefined (reading 'call')
    at Client.request
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/_/index.mjs:958:131)
    at Object.query
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/_/index.mjs:719:29)
    at Object.handler
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/routes/api/database.get.mjs:10:39)
    at Object.handler
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5106:24)
    at Object.handler
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5415:34)
    at Object.handler
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5177:31)
    at async toNodeHandle
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5447:7)
    at async ufetch
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5820:17)
    at async $fetchRaw2
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5693:26)
    at async $fetchRaw2
  (file:./home/mct/dev/notion-charts/.wrangler/tmp/pages-i7ppWE/chunks/runtime.mjs:5734:14)

@atinux
Copy link
Contributor

atinux commented Aug 21, 2024

Now you need to investigate by open those chunks as the right line and see where the call is read from

@mathieucollet
Copy link
Author

mathieucollet commented Aug 21, 2024

Ok, looks like it comes from the async method request (from the Notion-sdk), in the first line of the try:

async request({ path, method, query, body, auth, }) {
        this.log(logging_1.LogLevel.INFO, "request start", { method, path });
        // If the body is empty, don't send the body in the HTTP request
        const bodyAsJsonString = !body || Object.entries(body).length === 0
            ? undefined
            : JSON.stringify(body);
        const url = new URL(`${__classPrivateFieldGet(this, _Client_prefixUrl, "f")}${path}`);
        if (query) {
            for (const [key, value] of Object.entries(query)) {
                if (value !== undefined) {
                    if (Array.isArray(value)) {
                        value.forEach(val => url.searchParams.append(key, decodeURIComponent(val)));
                    }
                    else {
                        url.searchParams.append(key, String(value));
                    }
                }
            }
        }
        // Allow both client ID / client secret based auth as well as token based auth.
        let authorizationHeader;
        if (typeof auth === "object") {
            // Client ID and secret based auth is **ONLY** supported when using the
            // `/oauth/token` endpoint. If this is the case, handle formatting the
            // authorization header as required by `Basic` auth.
            const unencodedCredential = `${auth.client_id}:${auth.client_secret}`;
            const encodedCredential = Buffer.from(unencodedCredential).toString("base64");
            authorizationHeader = { authorization: `Basic ${encodedCredential}` };
        }
        else {
            // Otherwise format authorization header as `Bearer` token auth.
            authorizationHeader = this.authAsHeaders(auth);
        }
        const headers = {
            ...authorizationHeader,
            "Notion-Version": __classPrivateFieldGet(this, _Client_notionVersion, "f"),
            "user-agent": __classPrivateFieldGet(this, _Client_userAgent, "f"),
        };
        if (bodyAsJsonString !== undefined) {
            headers["content-type"] = "application/json";
        }
        try {
            const response = await errors_1.RequestTimeoutError.rejectAfterTimeout(__classPrivateFieldGet(this, _Client_fetch, "f").call(this, url.toString(), {
                method: method.toUpperCase(),
                headers,
                body: bodyAsJsonString,
                agent: __classPrivateFieldGet(this, _Client_agent, "f"),
            }), __classPrivateFieldGet(this, _Client_timeoutMs, "f"));
            const responseText = await response.text();
            if (!response.ok) {
                throw (0, errors_1.buildRequestError)(response, responseText);
            }
            const responseJson = JSON.parse(responseText);
            this.log(logging_1.LogLevel.INFO, `request success`, { method, path });
            return responseJson;
        }
        catch (error) {
            if (!(0, errors_1.isNotionClientError)(error)) {
                throw error;
            }
            // Log the error if it's one of our known error types
            this.log(logging_1.LogLevel.WARN, `request fail`, {
                code: error.code,
                message: error.message,
            });
            if ((0, errors_1.isHTTPResponseError)(error)) {
                // The response body may contain sensitive information so it is logged separately at the DEBUG level
                this.log(logging_1.LogLevel.DEBUG, `failed response body`, {
                    body: error.body,
                });
            }
            throw error;
        }
    }

@remihuigen
Copy link

@mathieucollet Same issue here

I can work around it by only using the SDK in local dev (Im using it to write a replica of notion DB's to R1), but I'm curious to know if you've found a solution!

@mathieucollet
Copy link
Author

Hey @remihuigen,

No, I haven't made any further progress. I understand that __classPrivateFieldGet(this, _Client_fetch, “f”) is undefined but at the moment I'm unable to say why!

@atinux
Copy link
Contributor

atinux commented Aug 23, 2024

Would you mind sharing a small GitHub repository with it so I can investigate?

@atinux
Copy link
Contributor

atinux commented Aug 23, 2024

Alright it seems Pooya (author of Nuxt 3 & Nitro) opened an issue in May 2021 about it 😄

makenotion/notion-sdk-js#38

Would you mind trying this comment?

makenotion/notion-sdk-js#38 (comment)

@mathieucollet
Copy link
Author

As I tried, I got another error:

 ERROR  [nuxt] [request error] [unhandled] [500] Failed to parse URL from [object Object]
  at node:internal/deps/undici/undici:12618:11  
  at process.processTicksAndRejections (node:internal/process/task_queues:95:5)


 ERROR  [nuxt] [request error] [unhandled] [500] Failed to parse URL from [object Object]
  at node:internal/deps/undici/undici:12618:11


 ERROR  [nuxt] [request error] [unhandled] [500] Failed to parse URL from [object Object]
  at node:internal/deps/undici/undici:12618:11  
  at process.processTicksAndRejections (node:internal/process/task_queues:95:5)


 ERROR  [nuxt] [request error] [unhandled] [500] Failed to parse URL from [object Object]
  at node:internal/deps/undici/undici:12618:11

I'll share you a project tomorow ;)

@mathieucollet
Copy link
Author

I just saw that the code in the comment is wrong, here is the right one.

const fetchWithMutableResponse = async (
  url: Parameters<typeof fetch>[0],
  init: Parameters<typeof fetch>[1]
): ReturnType<typeof fetch> => {
  const responseOriginal = await fetch(url?.toString(), init);
  return responseOriginal.clone();
};

const notion = new Client({
    auth: process.env.NUXT_NOTION_API_TOKEN,
    fetch: fetchWithMutableResponse
})

Typescript complaints about typing of the fetch passed + I have to make the notion token available.

I'll test it tomorow.

@mathieucollet
Copy link
Author

I can confirm that, using the code above and, of course, the useRuntimeConfig() for environment variables, Wrangler runs smoothly.

There's just a typing problem with this fetchWithMutableResponse.
image

Copy link
Contributor

atinux commented Aug 24, 2024

I am afraid that we cannot do much about it on our side and must be fixed in the Notion sdk package

@mathieucollet
Copy link
Author

No worries, it makes sense!

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

No branches or pull requests

3 participants