Skip to content

Commit

Permalink
(fix): add all tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fern-bot committed May 27, 2024
1 parent a820cb1 commit 78db005
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 94 deletions.
15 changes: 15 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# Specify files that shouldn't be modified by Fern

README.md

## Support content type on form data
src/core/form-data-utils
src/Client.ts
src/core/fetcher

## Change response signature
src/wrapper
src/index.ts

# Helper
src/generateFromHtml.ts

## Tests
tests/custom.test.ts
74 changes: 37 additions & 37 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,53 @@ name: ci
on: [push]

jobs:
compile:
runs-on: ubuntu-latest
compile:
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v3
steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
- name: Set up node
uses: actions/setup-node@v3

- name: Compile
run: yarn && yarn build
- name: Compile
run: yarn && yarn build

test:
runs-on: ubuntu-latest
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v3
steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
- name: Set up node
uses: actions/setup-node@v3

- name: Compile
run: yarn && yarn test
- name: Compile
run: yarn && yarn test

publish:
needs: [ compile, test ]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
publish:
needs: [compile, test]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v3
steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
- name: Set up node
uses: actions/setup-node@v3

- name: Install dependencies
run: yarn install
- name: Install dependencies
run: yarn install

- name: Build
run: yarn build
- name: Build
run: yarn build

- name: Publish to npm
run: |
npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
npm publish --access public
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish to npm
run: |
npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
npm publish --access public
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
34 changes: 14 additions & 20 deletions src/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ export class FileforgeClient {
requestOptions?: FileforgeClient.RequestOptions
): Promise<stream.Readable> {
const _request = new core.FormDataWrapper();
await _request.append("options", JSON.stringify(request.options));
const options = await serializers.GenerateRequestOptions.jsonOrThrow(request.options, {
unrecognizedObjectKeys: "passthrough",
allowUnrecognizedUnionMembers: false,
allowUnrecognizedEnumValues: false,
breadcrumbsPrefix: [""],
});
await _request.append("options", new Blob([JSON.stringify(options)], { type: "application/json" }));
for (const _file of files) {
await _request.append("files", _file);
}
Expand Down Expand Up @@ -73,24 +79,6 @@ export class FileforgeClient {

if (_response.error.reason === "status-code") {
switch (_response.error.statusCode) {
case 400:
throw new Fileforge.BadRequestError(
await serializers.ErrorSchema.parseOrThrow(_response.error.body, {
unrecognizedObjectKeys: "passthrough",
allowUnrecognizedUnionMembers: true,
allowUnrecognizedEnumValues: true,
breadcrumbsPrefix: ["response"],
})
);
case 401:
throw new Fileforge.UnauthorizedError(
await serializers.ErrorSchema.parseOrThrow(_response.error.body, {
unrecognizedObjectKeys: "passthrough",
allowUnrecognizedUnionMembers: true,
allowUnrecognizedEnumValues: true,
breadcrumbsPrefix: ["response"],
})
);
case 500:
throw new Fileforge.InternalServerError(_response.error.body);
case 502:
Expand Down Expand Up @@ -136,7 +124,13 @@ export class FileforgeClient {
requestOptions?: FileforgeClient.RequestOptions
): Promise<stream.Readable> {
const _request = new core.FormDataWrapper();
await _request.append("options", JSON.stringify(request.options));
const options = await serializers.MergeRequestOptions.jsonOrThrow(request.options, {
unrecognizedObjectKeys: "passthrough",
allowUnrecognizedUnionMembers: false,
allowUnrecognizedEnumValues: false,
breadcrumbsPrefix: [""],
});
await _request.append("options", new Blob([JSON.stringify(options)], { type: "application/json" }));
for (const _file of files) {
await _request.append("files", _file);
}
Expand Down
9 changes: 1 addition & 8 deletions src/core/fetcher/Fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,7 @@ async function fetcherImpl<R = unknown>(args: Fetcher.Args): Promise<APIResponse
// In Node.js environments, the SDK always uses`node-fetch`.
// If not in Node.js the SDK uses global fetch if available,
// and falls back to node-fetch.
const fetchFn =
RUNTIME.type === "node"
? // `.default` is required due to this issue:
// https://github.com/node-fetch/node-fetch/issues/450#issuecomment-387045223
((await import("node-fetch")).default as any)
: typeof fetch == "function"
? fetch
: ((await import("node-fetch")).default as any);
const fetchFn = typeof fetch == "function" ? fetch : ((await import("node-fetch")).default as any);

const makeRequest = async (): Promise<Response> => {
const signals: AbortSignal[] = [];
Expand Down
29 changes: 4 additions & 25 deletions src/core/form-data-utils/FormDataWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,25 @@ interface CrossPlatformFormData {

class FormDataRequestBody {
private fd: any;
private encoder: any;

constructor(fd: any) {
this.fd = fd;
}

async setup(): Promise<void> {
if (this.encoder == null && RUNTIME.type === "node") {
this.encoder = new (await import("form-data-encoder")).FormDataEncoder(this.fd);
}
}
async setup(): Promise<void> {}

/**
* @returns the multipart form data request
*/
public async getBody(): Promise<any> {
if (RUNTIME.type !== "node") {
return this.fd;
} else {
if (this.encoder == null) {
await this.setup();
}
return (await import("node:stream")).Readable.from(this.encoder);
}
return this.fd;
}

/**
* @returns headers that need to be added to the multipart form data request
*/
public async getHeaders(): Promise<Record<string, string>> {
if (RUNTIME.type !== "node") {
return {};
} else {
if (this.encoder == null) {
await this.setup();
}
return {
"Content-Length": this.encoder.length,
};
}
return {};
}
}

Expand All @@ -59,7 +38,7 @@ export class FormDataWrapper {
public async append(name: string, value: any): Promise<void> {
if (this.fd == null) {
if (RUNTIME.type === "node") {
this.fd = new (await import("formdata-node")).FormData();
this.fd = new FormData();
} else {
this.fd = new (await import("form-data")).default();
}
Expand Down
57 changes: 57 additions & 0 deletions src/generateFromHtml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Fileforge } from "index";
import { FileforgeClient, ResponseObject } from "./wrapper/FileforgeClient";
import mime from "mime-types";

export interface Asset {
path: string;
content: string;
}
export interface PathBuffer {
path: string;
content: Buffer;
}

export type AssetOrPathBuffer = Asset | PathBuffer;

export interface DocumentInput {
html: string;
fileName?: string;
test?: boolean;
host?: boolean;
expiresAt?: Date;
files?: AssetOrPathBuffer[];
}

export async function generateFromHtml(client: FileforgeClient, document: DocumentInput): Promise<ResponseObject> {
const files: AssetOrPathBuffer[] = document.files ?? [];
files.push({ path: "/index.html", content: document.html });

const test: boolean = document.test ?? true;
const save: boolean = document.host ?? false;

const optionsToUpload: Fileforge.GenerateRequestOptions = {
test: test,
host: save,
expiresAt: document.expiresAt ?? new Date(Date.now() + 24 * 60 * 60 * 1000),
fileName: document.fileName ?? "document",
};

const htmlBlob = new Blob([document.html], { type: "text/html" });
const htmlFile = new File([htmlBlob], "index.html", { type: "text/html" });

let filesToUpload = [htmlFile];

files.forEach((asset) => {
if (asset.content) {
const assetType = mime.lookup(asset.path) || "application/octet-stream";

const fileBlob = new Blob([asset.content], { type: assetType });
const file = new File([fileBlob], asset.path, { type: assetType });
filesToUpload.push(file);
}
});

return await client.generate(filesToUpload, {
options: optionsToUpload,
});
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * as Fileforge from "./api";
export { FileforgeClient } from "./Client";
export { FileforgeClient, ResponseStream, ResponseURL } from "./wrapper/FileforgeClient";
export { FileforgeEnvironment } from "./environments";
export { FileforgeError, FileforgeTimeoutError } from "./errors";
export { generateFromHtml } from "./generateFromHtml";
77 changes: 77 additions & 0 deletions src/wrapper/FileforgeClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { FileforgeClient as FernClient } from "../Client";
import * as fs from "fs";
import * as Fileforge from "../api/index";
import * as core from "../core";
import stream, { Stream } from "stream";

export interface ResponseURL {
url: string;
}

export interface ResponseStream {
file: stream.Readable;
}

export type ResponseObject = ResponseStream | ResponseURL;

export class FileforgeClient {
private client: FernClient;

constructor(options: FernClient.Options) {
this.client = new FernClient(options);
}

/**
* Generates a PDF document from web assets.
* @throws {@link Fileforge.BadRequestError}
* @throws {@link Fileforge.UnauthorizedError}
* @throws {@link Fileforge.InternalServerError}
* @throws {@link Fileforge.BadGatewayError}
*/
public async generate(
files: File[] | fs.ReadStream[],
request: Fileforge.GenerateRequest,
requestOptions?: FernClient.RequestOptions
): Promise<ResponseObject> {
const generated = await this.client.generate(files, request, requestOptions);
// read all contents
const chunks: any[] = [];
for await (let chunk of generated) {
chunks.push(chunk);
}
const value = Buffer.concat(chunks);
// try json parse
try {
return JSON.parse(value.toString()) as ResponseObject;
} catch {}
// return file
const { Readable } = await import("node:stream");
return { file: Readable.from(chunks) };
}

/**
* @throws {@link Fileforge.BadRequestError}
* @throws {@link Fileforge.UnauthorizedError}
* @throws {@link Fileforge.InternalServerError}
*/
public async merge(
files: File[] | fs.ReadStream[],
request: Fileforge.MergeRequest,
requestOptions?: FernClient.RequestOptions
): Promise<ResponseObject> {
const merged = await this.client.merge(files, request, requestOptions);
// read all contents
const chunks: any[] = [];
for await (let chunk of merged) {
chunks.push(chunk);
}
const value = Buffer.concat(chunks);
// try json parse
try {
return JSON.parse(value.toString()) as ResponseObject;
} catch {}
// return file
const { Readable } = await import("node:stream");
return { file: Readable.from(chunks) };
}
}
Loading

0 comments on commit 78db005

Please sign in to comment.