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

Can't upload worker #158

Closed
1bye opened this issue Mar 16, 2024 · 4 comments
Closed

Can't upload worker #158

1bye opened this issue Mar 16, 2024 · 4 comments
Labels
kind: generation-issue Categorizes issue or PR as related to the generation pipeline. service: workers Categorizes issue or PR as related to the Workers service.

Comments

@1bye
Copy link

1bye commented Mar 16, 2024

Hi!, I'm trying to upload the Cloudflare Worker, and receiving this error:

2 | import { castToError } from "./core.mjs";
3 | export class CloudflareError extends Error {
4 | }
5 | export class APIError extends CloudflareError {
6 |     constructor(status, error, message, headers) {
7 |         super(`${APIError.makeMessage(status, error, message)}`);
                                    ^
error: 400 {"result":null,"success":false,"errors":[{"code":10021,"message":"could not read content for part metadata"}],"messages":[]}
      at new CloudflareError (:1:33)
      at new APIError (/home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/error.mjs:7:9)
      at new BadRequestError (/home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/error.mjs:85:9)
      at generate (/home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/error.mjs:36:20)
      at /home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/core.mjs:289:25

Steps to reproduce:

My current code, (the config is correct):

import Cloudflare, { toFile } from "cloudflare";
import { config } from "$app/config";

const cf = new Cloudflare({
    apiToken: config.cloudflare.apiToken
});

cf.workers.scripts.update("test-worker", {
    "<any part name>": [
        await toFile(Buffer.from(`export default {
            async fetch() {
                return new Response("Hello!");
            }
        }`), "index.js", {
            type: "application/javascript"
        })
    ],
    metadata: {
        bindings: [],
        main_module: "index.js",
    },
    account_id: config.cloudflare.accountId
})

Additional Information

Also, after reviewing the cloudflare code, I tried following:

cf.workers.scripts.update("test-worker", {
    "index.js": new File([`export default {
            async fetch() {
                return new Response("Hello!");
            }
        }`], "index.js", {
        type: "application/javascript"
    }),
    metadata: new File([JSON.stringify({
        bindings: [],
        main_module: "index.js",
    })], "metadata.json", {
        type: "application/json"
    }),
    account_id: config.cloudflare.accountId
})

Which occurs another error:

2 | import { castToError } from "./core.mjs";
3 | export class CloudflareError extends Error {
4 | }
5 | export class APIError extends CloudflareError {
6 |     constructor(status, error, message, headers) {
7 |         super(`${APIError.makeMessage(status, error, message)}`);
                                    ^
error: 400 {"result":null,"success":false,"errors":[{"code":10021,"message":"Uncaught TypeError: Main module must be an ES module.\n"}],"messages":[]}
      at new CloudflareError (:1:33)
      at new APIError (/home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/error.mjs:7:9)
      at new BadRequestError (/home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/error.mjs:85:9)
      at generate (/home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/error.mjs:36:20)
      at /home/mrbye/Documents/GitHub/flow-server/node_modules/cloudflare/core.mjs:289:25
@jacobbednarz
Copy link
Member

your second example is how this should be done. here is my snippet using 3.0.0-beta.3:

import Cloudflare from "cloudflare";

const cf = new Cloudflare({
  apiEmail: process.env["CLOUDFLARE_EMAIL"],
  apiKey: process.env["CLOUDFLARE_API_KEY"],
});

cf.workers.scripts.update("test-typescript-worker", {
  "index.mjs": new File(
    [
      `export default {
        async fetch() {
          return new Response("Hello!");
        }
    }`,
    ],
    "index.mjs",
    {
      type: "application/javascript+module",
    }
  ),
  metadata: new File(
    [
      JSON.stringify({
        bindings: [],
        main_module: "index.mjs",
      }),
    ],
    null,
    {
      type: "application/json",
    }
  ),
  account_id: "f037e56e89293a057740de681ac9abbe",
});

unfortunately, the bit that isn't working is the content-type handling. here is an example of a working payload (from Go):

--f396ba51d2fc6a4a456bbf43a15e20534fcb5b145d69c2ead78b274bc40c
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{"main_module":"worker.mjs","bindings":[]}
--f396ba51d2fc6a4a456bbf43a15e20534fcb5b145d69c2ead78b274bc40c
Content-Disposition: form-data; name="worker.mjs"; filename="worker.mjs"
Content-Type: application/javascript+module

export default {
    async fetch() {
        return new Response("Hello!");
    }
}

--f396ba51d2fc6a4a456bbf43a15e20534fcb5b145d69c2ead78b274bc40c--

note the content-types of application/json and application/javascript+module respectively.

however, when executing from the SDK, i can see that the content-types are not being picked up correctly. instead, they are defaulting to application/octet-stream.

---WebkitFormBoundaryf1f6a8736e384264b6e541aad3605aaf
Content-Disposition: form-data; name="index.mjs"; filename="index.mjs"
Content-Type: application/octet-stream

export default {
        async fetch() {
          return new Response("Hello!");
        }
    }
---WebkitFormBoundaryf1f6a8736e384264b6e541aad3605aaf
Content-Disposition: form-data; name="metadata"
Content-Type: application/octet-stream

{"bindings":[],"main_module":"index.mjs"}
---WebkitFormBoundaryf1f6a8736e384264b6e541aad3605aaf--

this will need investigation as it looks like this either specific to the SDK or node. new File within Workers seems to be doing the right thing.

@jacobbednarz
Copy link
Member

this was a bug in our handling of the types being passed through. this is now resolved in v3.0.0-beta.8

working example

import Cloudflare from "cloudflare";

const cf = new Cloudflare({
  apiToken: "<token>"
});

cf.workers.scripts.update("test-worker", {
  "index.js": new File(
    [
      `export default {
          async fetch() {
              return new Response("Hello!");
          }
      }`,
    ],
    "index.js",
    {
      type: "application/javascript+module",
    }
  ),
  metadata: new File(
    [
      JSON.stringify({
        bindings: [],
        main_module: "index.js",
      }),
    ],
    "metadata.json",
    {
      type: "application/json",
    }
  ),
  account_id: "<account id>",
});

@jacobbednarz jacobbednarz added service: workers Categorizes issue or PR as related to the Workers service. kind: generation-issue Categorizes issue or PR as related to the generation pipeline. labels Mar 20, 2024
@1bye
Copy link
Author

1bye commented Mar 23, 2024

@jacobbednarz Thanks

@zoubingwu
Copy link

this was a bug in our handling of the types being passed through. this is now resolved in v3.0.0-beta.8

working example

import Cloudflare from "cloudflare";

const cf = new Cloudflare({
  apiToken: "<token>"
});

cf.workers.scripts.update("test-worker", {
  "index.js": new File(
    [
      `export default {
          async fetch() {
              return new Response("Hello!");
          }
      }`,
    ],
    "index.js",
    {
      type: "application/javascript+module",
    }
  ),
  metadata: new File(
    [
      JSON.stringify({
        bindings: [],
        main_module: "index.js",
      }),
    ],
    "metadata.json",
    {
      type: "application/json",
    }
  ),
  account_id: "<account id>",
});

@jacobbednarz After some testing, this code indeed works. However, this won't be compliled when using typescript, the definition of the type is completely incorrect. Are there any plans to fix it?

the <any part name> field here is fixed but instead it should be and record type so the key can be arbitrary?

image

and metadata field here only requires a plain object but in this working code, it have to be a File:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: generation-issue Categorizes issue or PR as related to the generation pipeline. service: workers Categorizes issue or PR as related to the Workers service.
Projects
None yet
Development

No branches or pull requests

3 participants