diff --git a/src/client.ts b/src/client.ts index 608b318..e866d01 100644 --- a/src/client.ts +++ b/src/client.ts @@ -17,6 +17,7 @@ import * as Errors from './core/error'; import * as Pagination from './core/pagination'; import { AbstractPage, type SkipLimitParams, SkipLimitResponse } from './core/pagination'; import * as Uploads from './core/uploads'; +import { maybeMultipartFormRequestOptions } from './internal/uploads'; import * as API from './resources/index'; import { APIPromise } from './core/api-promise'; import { @@ -393,6 +394,12 @@ export class PostGrid { await this.prepareOptions(options); + // if body contains file uploads, convert to multipart/form-data (fastest way and making compiler happy) + const withMultipart = await maybeMultipartFormRequestOptions(options, this); + if (withMultipart.body !== options.body) { + options.body = withMultipart.body; + } + const { req, url, timeout } = await this.buildRequest(options, { retryCount: maxRetries - retriesRemaining, }); diff --git a/src/resources/print-mail/letters.ts b/src/resources/print-mail/letters.ts index 9fc64c0..ef24147 100644 --- a/src/resources/print-mail/letters.ts +++ b/src/resources/print-mail/letters.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../core/resource'; +import type { Uploadable } from '../../core/uploads'; import * as ContactsAPI from './contacts'; import * as PrintMailAPI from './print-mail'; import { APIPromise } from '../../core/api-promise'; @@ -108,7 +109,7 @@ export interface AttachedPdf { /** * The file (multipart form upload) or URL pointing to a PDF for the attached PDF. */ - file: string; + file: string | Uploadable; /** * Enum representing the placement of the attached PDF. @@ -405,7 +406,7 @@ export namespace PlasticCard { * A URL pointing to a PDF file for the double-sided plastic card or the file * itself. */ - pdf?: string; + pdf?: string | Uploadable; } /** @@ -422,7 +423,7 @@ export namespace PlasticCard { * A URL pointing to a PDF file for the single-sided plastic card or the PDF file * itself. */ - pdf?: string; + pdf?: string | Uploadable; /** * The template ID for the single-sided plastic card. @@ -596,7 +597,7 @@ export declare namespace LetterCreateParams { /** * A URL pointing to a PDF file for the letter or the PDF file itself. */ - pdf: string; + pdf: string | Uploadable; /** * The recipient of this order. You can either supply the contact information diff --git a/src/resources/print-mail/order-profiles/cheques.ts b/src/resources/print-mail/order-profiles/cheques.ts index 7bd51e6..ad6e2c6 100644 --- a/src/resources/print-mail/order-profiles/cheques.ts +++ b/src/resources/print-mail/order-profiles/cheques.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../core/resource'; +import type { Uploadable } from '../../../core/uploads'; import * as ChequesAPI from '../cheques'; import { APIPromise } from '../../../core/api-promise'; import { PagePromise, SkipLimit, type SkipLimitParams } from '../../../core/pagination'; @@ -387,7 +388,7 @@ export interface ChequeCreateParams { * Body param: PDF file for an optional attached letter. Cannot be used with * `letterHTML` or `letterTemplate`. Input only. */ - letterPDF?: string; + letterPDF?: string | Uploadable; /** * Body param: ID of a template for an optional attached letter. Cannot be used @@ -494,7 +495,7 @@ export interface ChequeUpdateParams { * Body param: PDF file for an optional attached letter. Cannot be used with * `letterHTML` or `letterTemplate`. Input only. */ - letterPDF?: string; + letterPDF?: string | Uploadable; /** * Body param: ID of a template for an optional attached letter. Cannot be used diff --git a/src/resources/print-mail/order-profiles/letters.ts b/src/resources/print-mail/order-profiles/letters.ts index bf601bd..1b35ea5 100644 --- a/src/resources/print-mail/order-profiles/letters.ts +++ b/src/resources/print-mail/order-profiles/letters.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../core/resource'; +import type { Uploadable } from '../../../core/uploads'; import * as LettersAPI from '../letters'; import { APIPromise } from '../../../core/api-promise'; import { PagePromise, SkipLimit, type SkipLimitParams } from '../../../core/pagination'; @@ -337,7 +338,7 @@ export interface LetterCreateParams { * Body param: A PDF file containing the letter content. Cannot be used with * `template`. */ - pdf?: string; + pdf?: string | Uploadable; /** * Body param: Specifies which page number should be perforated (if any). @@ -446,7 +447,7 @@ export interface LetterUpdateParams { * Body param: A PDF file containing the letter content. Cannot be used with * `template`. */ - pdf?: string; + pdf?: string | Uploadable; /** * Body param: Specifies which page number should be perforated (if any). diff --git a/src/resources/print-mail/order-profiles/postcards.ts b/src/resources/print-mail/order-profiles/postcards.ts index 02a2ee5..76149e5 100644 --- a/src/resources/print-mail/order-profiles/postcards.ts +++ b/src/resources/print-mail/order-profiles/postcards.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../core/resource'; +import type { Uploadable } from '../../../core/uploads'; import { APIPromise } from '../../../core/api-promise'; import { PagePromise, SkipLimit, type SkipLimitParams } from '../../../core/pagination'; import { RequestOptions } from '../../../internal/request-options'; @@ -296,7 +297,7 @@ export interface PostcardCreateParams { * Body param: A 2-page PDF file containing the postcard content (front and back). * Cannot be used with `frontTemplate`/`backTemplate`. */ - pdf?: string; + pdf?: string | Uploadable; } export interface PostcardRetrieveParams { @@ -376,7 +377,7 @@ export interface PostcardUpdateParams { * Body param: A 2-page PDF file containing the postcard content (front and back). * Cannot be used with `frontTemplate`/`backTemplate`. */ - pdf?: string; + pdf?: string | Uploadable; } export interface PostcardListParams extends SkipLimitParams { diff --git a/src/resources/print-mail/order-profiles/self-mailers.ts b/src/resources/print-mail/order-profiles/self-mailers.ts index f27b2f4..1834325 100644 --- a/src/resources/print-mail/order-profiles/self-mailers.ts +++ b/src/resources/print-mail/order-profiles/self-mailers.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../core/resource'; +import type { Uploadable } from '../../../core/uploads'; import { APIPromise } from '../../../core/api-promise'; import { PagePromise, SkipLimit, type SkipLimitParams } from '../../../core/pagination'; import { RequestOptions } from '../../../internal/request-options'; @@ -303,7 +304,7 @@ export interface SelfMailerCreateParams { * Body param: A 2-page PDF file containing the self-mailer content (inside and * outside). Cannot be used with `insideTemplate`/`outsideTemplate`. */ - pdf?: string; + pdf?: string | Uploadable; } export interface SelfMailerRetrieveParams { @@ -387,7 +388,7 @@ export interface SelfMailerUpdateParams { * Body param: A 2-page PDF file containing the self-mailer content (inside and * outside). Cannot be used with `insideTemplate`/`outsideTemplate`. */ - pdf?: string; + pdf?: string | Uploadable; } export interface SelfMailerListParams extends SkipLimitParams { diff --git a/src/resources/print-mail/postcards.ts b/src/resources/print-mail/postcards.ts index 64ea80a..0720cea 100644 --- a/src/resources/print-mail/postcards.ts +++ b/src/resources/print-mail/postcards.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../core/resource'; +import type { Uploadable } from '../../core/uploads'; import * as ContactsAPI from './contacts'; import * as PrintMailAPI from './print-mail'; import * as OrderProfilesPostcardsAPI from './order-profiles/postcards'; @@ -404,7 +405,7 @@ export declare namespace PostcardCreateParams { * A URL pointing to a 2 page PDF file. The first page is the front of the postcard * and the second page is the back (where the address will be stamped on). */ - pdf: string; + pdf: string | Uploadable; /** * Enum representing the supported postcard sizes. @@ -489,7 +490,7 @@ export declare namespace PostcardCreateParams { * A 2 page PDF file. The first page is the front of the postcard and the second * page is the back (where the address will be stamped on). */ - pdf: string; + pdf: string | Uploadable; /** * Enum representing the supported postcard sizes. diff --git a/src/resources/print-mail/self-mailers.ts b/src/resources/print-mail/self-mailers.ts index faccc37..b45754e 100644 --- a/src/resources/print-mail/self-mailers.ts +++ b/src/resources/print-mail/self-mailers.ts @@ -1,6 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../core/resource'; +import type { Uploadable } from '../../core/uploads'; import * as ContactsAPI from './contacts'; import * as PrintMailAPI from './print-mail'; import * as OrderProfilesSelfMailersAPI from './order-profiles/self-mailers'; @@ -412,7 +413,7 @@ export declare namespace SelfMailerCreateParams { * self-mailer and the second page is the outside (where the address will be * stamped on). */ - pdf: string; + pdf: string | Uploadable; /** * Enum representing the supported self-mailer sizes. @@ -496,7 +497,7 @@ export declare namespace SelfMailerCreateParams { * A 2 page PDF file. The first page is the inside of the self-mailer and the * second page is the outside (where the address will be stamped on). */ - pdf: string; + pdf: string | Uploadable; /** * Enum representing the supported self-mailer sizes. diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 6a964a1..bf63d18 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import type { ResponseLike } from 'postgrid-node/internal/to-file'; import { toFile } from 'postgrid-node/core/uploads'; +import { maybeMultipartFormRequestOptions } from 'postgrid-node/internal/uploads'; import { File } from 'node:buffer'; class MyClass { @@ -105,3 +106,56 @@ describe('missing File error message', () => { ); }); }); + +describe('maybeMultipartFormRequestOptions', () => { + it('returns opts unchanged when body has no uploadable value', async () => { + const body = { + from: 'contact_1', + to: 'contact_2', + pdf: 'https://example.com/letter.pdf', + }; + const opts = { body }; + const result = await maybeMultipartFormRequestOptions(opts, fetch); + expect(result).toBe(opts); + expect(result.body).toBe(body); + }); + + it('returns new opts with FormData body when body contains a File', async () => { + const pdfFile = new File(['fake content'], 'letter.pdf', { type: 'application/pdf' }); + const body = { + from: 'contact_1', + to: 'contact_2', + pdf: pdfFile, + }; + const opts = { body }; + const result = await maybeMultipartFormRequestOptions(opts, fetch); + expect(result).not.toBe(opts); + expect(result.body).toBeInstanceOf(FormData); + const form = result.body as FormData; + expect(form.get('from')).toBe('contact_1'); + expect(form.get('to')).toBe('contact_2'); + const pdfPart = form.get('pdf'); + expect(pdfPart).toBeInstanceOf(Blob); + expect((pdfPart as File).name).toBe('letter.pdf'); + }); + + it('works with toFile(Buffer) for PDF upload path', async () => { + const buffer = Buffer.from('fake content'); + const pdfFile = await toFile(buffer, 'letter.pdf'); + const body = { + from: 'contact_1', + to: 'contact_2', + pdf: pdfFile, + }; + const opts = { body }; + const result = await maybeMultipartFormRequestOptions(opts, fetch); + expect(result).not.toBe(opts); + expect(result.body).toBeInstanceOf(FormData); + const form = result.body as FormData; + expect(form.get('from')).toBe('contact_1'); + expect(form.get('to')).toBe('contact_2'); + const pdfPart = form.get('pdf'); + expect(pdfPart).toBeInstanceOf(Blob); + expect((pdfPart as File).name).toBe('letter.pdf'); + }); +});