Edits history of script submission #23140 for ' Upload File (notion)'

  • bun
    One script reply has been approved by the moderators
    Ap­pro­ved
    import * as wmill from "windmill-client"
    import { S3Object } from "windmill-client"
    
    /**
     * Upload File
     * Upload a file from Windmill object storage to Notion. Files over 20 MiB are sent in 10 MiB parts. Pass `attach_to_page_id` to append it to a page as a file block; otherwise use the returned `id` within an hour (as a `file_upload` in a block, cover, icon or files property) or it expires. Free workspaces cap files at 5 MiB.
     */
    export async function main(
      auth: RT.Notion,
      file: S3Object,
      filename: string,
      content_type: string | undefined,
      attach_to_page_id: string | undefined
    ) {
      const bytes = await wmill.loadS3File(file)
      if (!bytes) {
        throw new Error("Could not load the file from object storage")
      }
      const headers = {
        Authorization: `Bearer ${auth.token}`,
        Accept: "application/json",
        "Notion-Version": "2026-03-11",
      }
      const call = async (path: string, init: RequestInit) => {
        const response = await fetch(`https://api.notion.com/v1/${path}`, {
          ...init,
          headers: { ...headers, ...init.headers },
        })
        if (!response.ok) {
          throw new Error(`${response.status} ${await response.text()}`)
        }
        return await response.json()
      }
    
      const PART = 10 * 1024 * 1024
      const parts =
        bytes.length > 20 * 1024 * 1024 ? Math.ceil(bytes.length / PART) : 1
      const create: { [key: string]: any } = { filename }
      if (content_type !== undefined && content_type !== "") {
        create.content_type = content_type
      }
      if (parts > 1) {
        create.mode = "multi_part"
        create.number_of_parts = parts
      }
      const upload = await call("file_uploads", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(create),
      })
    
      let result = upload
      for (let i = 0; i < parts; i++) {
        const form = new FormData()
        const chunk = parts > 1 ? bytes.subarray(i * PART, (i + 1) * PART) : bytes
        form.append(
          "file",
          new Blob([chunk], { type: content_type || undefined }),
          filename
        )
        if (parts > 1) form.append("part_number", String(i + 1))
        result = await call(`file_uploads/${upload.id}/send`, {
          method: "POST",
          body: form,
        })
      }
      if (parts > 1) {
        result = await call(`file_uploads/${upload.id}/complete`, {
          method: "POST",
        })
      }
    
      if (attach_to_page_id !== undefined && attach_to_page_id !== "") {
        await call(`blocks/${attach_to_page_id}/children`, {
          method: "PATCH",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            children: [
              {
                type: "file",
                file: { type: "file_upload", file_upload: { id: upload.id } },
              },
            ],
          }),
        })
      }
    
      return result
    }
    

    Submitted by hugo989 4 hours ago