Rebuild fern client sdk to 1.06 (#4331)
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
import * as Skyvern from "./api/index.js";
|
||||
import { Scripts } from "./api/resources/scripts/client/Client.js";
|
||||
import { Workflows } from "./api/resources/workflows/client/Client.js";
|
||||
import type { BaseClientOptions, BaseRequestOptions } from "./BaseClient.js";
|
||||
import { mergeHeaders, mergeOnlyDefinedHeaders } from "./core/headers.js";
|
||||
import * as core from "./core/index.js";
|
||||
@@ -17,7 +16,6 @@ export declare namespace SkyvernClient {
|
||||
|
||||
export class SkyvernClient {
|
||||
protected readonly _options: SkyvernClient.Options;
|
||||
protected _workflows: Workflows | undefined;
|
||||
protected _scripts: Scripts | undefined;
|
||||
|
||||
constructor(_options: SkyvernClient.Options = {}) {
|
||||
@@ -28,8 +26,8 @@ export class SkyvernClient {
|
||||
"x-api-key": _options?.apiKey,
|
||||
"X-Fern-Language": "JavaScript",
|
||||
"X-Fern-SDK-Name": "@skyvern/client",
|
||||
"X-Fern-SDK-Version": "1.0.3",
|
||||
"User-Agent": "@skyvern/client/1.0.3",
|
||||
"X-Fern-SDK-Version": "1.0.6",
|
||||
"User-Agent": "@skyvern/client/1.0.6",
|
||||
"X-Fern-Runtime": core.RUNTIME.type,
|
||||
"X-Fern-Runtime-Version": core.RUNTIME.version,
|
||||
},
|
||||
@@ -38,10 +36,6 @@ export class SkyvernClient {
|
||||
};
|
||||
}
|
||||
|
||||
public get workflows(): Workflows {
|
||||
return (this._workflows ??= new Workflows(this._options));
|
||||
}
|
||||
|
||||
public get scripts(): Scripts {
|
||||
return (this._scripts ??= new Scripts(this._options));
|
||||
}
|
||||
@@ -948,6 +942,7 @@ export class SkyvernClient {
|
||||
* Retry sending the webhook for a run
|
||||
*
|
||||
* @param {string} runId - The id of the task run or the workflow run.
|
||||
* @param {Skyvern.RetryRunWebhookRequest} request
|
||||
* @param {SkyvernClient.RequestOptions} requestOptions - Request-specific configuration.
|
||||
*
|
||||
* @throws {@link Skyvern.UnprocessableEntityError}
|
||||
@@ -957,13 +952,15 @@ export class SkyvernClient {
|
||||
*/
|
||||
public retryRunWebhook(
|
||||
runId: string,
|
||||
request?: Skyvern.RetryRunWebhookRequest,
|
||||
requestOptions?: SkyvernClient.RequestOptions,
|
||||
): core.HttpResponsePromise<unknown> {
|
||||
return core.HttpResponsePromise.fromPromise(this.__retryRunWebhook(runId, requestOptions));
|
||||
return core.HttpResponsePromise.fromPromise(this.__retryRunWebhook(runId, request, requestOptions));
|
||||
}
|
||||
|
||||
private async __retryRunWebhook(
|
||||
runId: string,
|
||||
request?: Skyvern.RetryRunWebhookRequest,
|
||||
requestOptions?: SkyvernClient.RequestOptions,
|
||||
): Promise<core.WithRawResponse<unknown>> {
|
||||
const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
|
||||
@@ -980,7 +977,10 @@ export class SkyvernClient {
|
||||
),
|
||||
method: "POST",
|
||||
headers: _headers,
|
||||
contentType: "application/json",
|
||||
queryParameters: requestOptions?.queryParams,
|
||||
requestType: "json",
|
||||
body: request != null ? request : undefined,
|
||||
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
|
||||
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
||||
abortSignal: requestOptions?.abortSignal,
|
||||
@@ -1102,6 +1102,91 @@ export class SkyvernClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Skyvern.BodyUploadFileV1UploadFilePost} request
|
||||
* @param {SkyvernClient.RequestOptions} requestOptions - Request-specific configuration.
|
||||
*
|
||||
* @throws {@link Skyvern.UnprocessableEntityError}
|
||||
*
|
||||
* @example
|
||||
* import { createReadStream } from "fs";
|
||||
* await client.uploadFile({
|
||||
* file: fs.createReadStream("/path/to/your/file")
|
||||
* })
|
||||
*/
|
||||
public uploadFile(
|
||||
request: Skyvern.BodyUploadFileV1UploadFilePost,
|
||||
requestOptions?: SkyvernClient.RequestOptions,
|
||||
): core.HttpResponsePromise<Skyvern.UploadFileResponse> {
|
||||
return core.HttpResponsePromise.fromPromise(this.__uploadFile(request, requestOptions));
|
||||
}
|
||||
|
||||
private async __uploadFile(
|
||||
request: Skyvern.BodyUploadFileV1UploadFilePost,
|
||||
requestOptions?: SkyvernClient.RequestOptions,
|
||||
): Promise<core.WithRawResponse<Skyvern.UploadFileResponse>> {
|
||||
const _request = await core.newFormData();
|
||||
await _request.appendFile("file", request.file);
|
||||
const _maybeEncodedRequest = await _request.getRequest();
|
||||
const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
|
||||
this._options?.headers,
|
||||
mergeOnlyDefinedHeaders({
|
||||
"x-api-key": requestOptions?.apiKey ?? this._options?.apiKey,
|
||||
..._maybeEncodedRequest.headers,
|
||||
}),
|
||||
requestOptions?.headers,
|
||||
);
|
||||
const _response = await core.fetcher({
|
||||
url: core.url.join(
|
||||
(await core.Supplier.get(this._options.baseUrl)) ??
|
||||
(await core.Supplier.get(this._options.environment)) ??
|
||||
environments.SkyvernEnvironment.Cloud,
|
||||
"v1/upload_file",
|
||||
),
|
||||
method: "POST",
|
||||
headers: _headers,
|
||||
queryParameters: requestOptions?.queryParams,
|
||||
requestType: "file",
|
||||
duplex: _maybeEncodedRequest.duplex,
|
||||
body: _maybeEncodedRequest.body,
|
||||
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
|
||||
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
||||
abortSignal: requestOptions?.abortSignal,
|
||||
});
|
||||
if (_response.ok) {
|
||||
return { data: _response.body as Skyvern.UploadFileResponse, rawResponse: _response.rawResponse };
|
||||
}
|
||||
|
||||
if (_response.error.reason === "status-code") {
|
||||
switch (_response.error.statusCode) {
|
||||
case 422:
|
||||
throw new Skyvern.UnprocessableEntityError(_response.error.body as unknown, _response.rawResponse);
|
||||
default:
|
||||
throw new errors.SkyvernError({
|
||||
statusCode: _response.error.statusCode,
|
||||
body: _response.error.body,
|
||||
rawResponse: _response.rawResponse,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
switch (_response.error.reason) {
|
||||
case "non-json":
|
||||
throw new errors.SkyvernError({
|
||||
statusCode: _response.error.statusCode,
|
||||
body: _response.error.rawBody,
|
||||
rawResponse: _response.rawResponse,
|
||||
});
|
||||
case "timeout":
|
||||
throw new errors.SkyvernTimeoutError("Timeout exceeded when calling POST /v1/upload_file.");
|
||||
case "unknown":
|
||||
throw new errors.SkyvernError({
|
||||
message: _response.error.errorMessage,
|
||||
rawResponse: _response.rawResponse,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all browser profiles for the organization
|
||||
*
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// This file was auto-generated by Fern from our API Definition.
|
||||
|
||||
import type * as core from "../../../core/index.js";
|
||||
|
||||
/**
|
||||
* @example
|
||||
* {
|
||||
* file: fs.createReadStream("/path/to/your/file")
|
||||
* }
|
||||
*/
|
||||
export interface BodyUploadFileV1UploadFilePost {
|
||||
file: core.file.Uploadable;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export type { BodyUploadFileV1UploadFilePost } from "./BodyUploadFileV1UploadFilePost.js";
|
||||
export type { CreateBrowserProfileRequest } from "./CreateBrowserProfileRequest.js";
|
||||
export type { CreateBrowserSessionRequest } from "./CreateBrowserSessionRequest.js";
|
||||
export type { CreateCredentialRequest } from "./CreateCredentialRequest.js";
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
export * as scripts from "./scripts/index.js";
|
||||
export * from "./workflows/client/requests/index.js";
|
||||
export * as workflows from "./workflows/index.js";
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
// This file was auto-generated by Fern from our API Definition.
|
||||
|
||||
import type { BaseClientOptions, BaseRequestOptions } from "../../../../BaseClient.js";
|
||||
import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../core/headers.js";
|
||||
import * as core from "../../../../core/index.js";
|
||||
import * as environments from "../../../../environments.js";
|
||||
import * as errors from "../../../../errors/index.js";
|
||||
import * as Skyvern from "../../../index.js";
|
||||
|
||||
export declare namespace Workflows {
|
||||
export interface Options extends BaseClientOptions {}
|
||||
|
||||
export interface RequestOptions extends BaseRequestOptions {}
|
||||
}
|
||||
|
||||
export class Workflows {
|
||||
protected readonly _options: Workflows.Options;
|
||||
|
||||
constructor(_options: Workflows.Options = {}) {
|
||||
this._options = _options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or unset a workflow as a template.
|
||||
*
|
||||
* Template status is stored at the workflow_permanent_id level (not per-version),
|
||||
* meaning all versions of a workflow share the same template status.
|
||||
*
|
||||
* @param {string} workflowPermanentId
|
||||
* @param {Skyvern.SetWorkflowTemplateStatusV1WorkflowsWorkflowPermanentIdTemplatePutRequest} request
|
||||
* @param {Workflows.RequestOptions} requestOptions - Request-specific configuration.
|
||||
*
|
||||
* @throws {@link Skyvern.UnprocessableEntityError}
|
||||
*
|
||||
* @example
|
||||
* await client.workflows.setWorkflowTemplateStatus("workflow_permanent_id", {
|
||||
* is_template: true
|
||||
* })
|
||||
*/
|
||||
public setWorkflowTemplateStatus(
|
||||
workflowPermanentId: string,
|
||||
request: Skyvern.SetWorkflowTemplateStatusV1WorkflowsWorkflowPermanentIdTemplatePutRequest,
|
||||
requestOptions?: Workflows.RequestOptions,
|
||||
): core.HttpResponsePromise<Record<string, unknown>> {
|
||||
return core.HttpResponsePromise.fromPromise(
|
||||
this.__setWorkflowTemplateStatus(workflowPermanentId, request, requestOptions),
|
||||
);
|
||||
}
|
||||
|
||||
private async __setWorkflowTemplateStatus(
|
||||
workflowPermanentId: string,
|
||||
request: Skyvern.SetWorkflowTemplateStatusV1WorkflowsWorkflowPermanentIdTemplatePutRequest,
|
||||
requestOptions?: Workflows.RequestOptions,
|
||||
): Promise<core.WithRawResponse<Record<string, unknown>>> {
|
||||
const { is_template: isTemplate } = request;
|
||||
const _queryParams: Record<string, string | string[] | object | object[] | null> = {};
|
||||
_queryParams.is_template = isTemplate.toString();
|
||||
const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
|
||||
this._options?.headers,
|
||||
mergeOnlyDefinedHeaders({ "x-api-key": requestOptions?.apiKey ?? this._options?.apiKey }),
|
||||
requestOptions?.headers,
|
||||
);
|
||||
const _response = await core.fetcher({
|
||||
url: core.url.join(
|
||||
(await core.Supplier.get(this._options.baseUrl)) ??
|
||||
(await core.Supplier.get(this._options.environment)) ??
|
||||
environments.SkyvernEnvironment.Cloud,
|
||||
`v1/workflows/${core.url.encodePathParam(workflowPermanentId)}/template`,
|
||||
),
|
||||
method: "PUT",
|
||||
headers: _headers,
|
||||
queryParameters: { ..._queryParams, ...requestOptions?.queryParams },
|
||||
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
|
||||
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
||||
abortSignal: requestOptions?.abortSignal,
|
||||
});
|
||||
if (_response.ok) {
|
||||
return { data: _response.body as Record<string, unknown>, rawResponse: _response.rawResponse };
|
||||
}
|
||||
|
||||
if (_response.error.reason === "status-code") {
|
||||
switch (_response.error.statusCode) {
|
||||
case 422:
|
||||
throw new Skyvern.UnprocessableEntityError(_response.error.body as unknown, _response.rawResponse);
|
||||
default:
|
||||
throw new errors.SkyvernError({
|
||||
statusCode: _response.error.statusCode,
|
||||
body: _response.error.body,
|
||||
rawResponse: _response.rawResponse,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
switch (_response.error.reason) {
|
||||
case "non-json":
|
||||
throw new errors.SkyvernError({
|
||||
statusCode: _response.error.statusCode,
|
||||
body: _response.error.rawBody,
|
||||
rawResponse: _response.rawResponse,
|
||||
});
|
||||
case "timeout":
|
||||
throw new errors.SkyvernTimeoutError(
|
||||
"Timeout exceeded when calling PUT /v1/workflows/{workflow_permanent_id}/template.",
|
||||
);
|
||||
case "unknown":
|
||||
throw new errors.SkyvernError({
|
||||
message: _response.error.errorMessage,
|
||||
rawResponse: _response.rawResponse,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./requests/index.js";
|
||||
@@ -1,11 +0,0 @@
|
||||
// This file was auto-generated by Fern from our API Definition.
|
||||
|
||||
/**
|
||||
* @example
|
||||
* {
|
||||
* is_template: true
|
||||
* }
|
||||
*/
|
||||
export interface SetWorkflowTemplateStatusV1WorkflowsWorkflowPermanentIdTemplatePutRequest {
|
||||
is_template: boolean;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export type { SetWorkflowTemplateStatusV1WorkflowsWorkflowPermanentIdTemplatePutRequest } from "./SetWorkflowTemplateStatusV1WorkflowsWorkflowPermanentIdTemplatePutRequest.js";
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./client/index.js";
|
||||
@@ -7,7 +7,7 @@ export interface PromptAction {
|
||||
/** The prompt to send to the LLM */
|
||||
prompt: string;
|
||||
/** Optional JSON schema to structure the response */
|
||||
schema?: Record<string, unknown>;
|
||||
response_schema?: Record<string, unknown>;
|
||||
/** Optional model configuration */
|
||||
model?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was auto-generated by Fern from our API Definition.
|
||||
|
||||
export interface RetryRunWebhookRequest {
|
||||
/** Optional webhook URL to send the payload to instead of the stored configuration */
|
||||
webhook_url?: string;
|
||||
}
|
||||
8
skyvern-ts/client/src/api/types/UploadFileResponse.ts
Normal file
8
skyvern-ts/client/src/api/types/UploadFileResponse.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// This file was auto-generated by Fern from our API Definition.
|
||||
|
||||
export interface UploadFileResponse {
|
||||
/** S3 URI where the file was uploaded */
|
||||
s3_uri: string;
|
||||
/** Presigned URL to access the uploaded file */
|
||||
presigned_url: string;
|
||||
}
|
||||
@@ -96,6 +96,7 @@ export * from "./PdfParserBlockYaml.js";
|
||||
export * from "./PromptAction.js";
|
||||
export * from "./PromptBranchCriteria.js";
|
||||
export * from "./ProxyLocation.js";
|
||||
export * from "./RetryRunWebhookRequest.js";
|
||||
export * from "./RunEngine.js";
|
||||
export * from "./RunSdkActionRequestAction.js";
|
||||
export * from "./RunSdkActionResponse.js";
|
||||
@@ -127,6 +128,7 @@ export * from "./ThoughtType.js";
|
||||
export * from "./TotpCode.js";
|
||||
export * from "./TotpType.js";
|
||||
export * from "./UploadFileAction.js";
|
||||
export * from "./UploadFileResponse.js";
|
||||
export * from "./UploadToS3Block.js";
|
||||
export * from "./UploadToS3BlockYaml.js";
|
||||
export * from "./UrlBlock.js";
|
||||
|
||||
1
skyvern-ts/client/src/core/exports.ts
Normal file
1
skyvern-ts/client/src/core/exports.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./file/exports.js";
|
||||
1
skyvern-ts/client/src/core/file/exports.ts
Normal file
1
skyvern-ts/client/src/core/file/exports.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type { Uploadable } from "./types.js";
|
||||
217
skyvern-ts/client/src/core/file/file.ts
Normal file
217
skyvern-ts/client/src/core/file/file.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import type { Uploadable } from "./types.js";
|
||||
|
||||
export async function toBinaryUploadRequest(
|
||||
file: Uploadable,
|
||||
): Promise<{ body: Uploadable.FileLike; headers?: Record<string, string> }> {
|
||||
const { data, filename, contentLength, contentType } = await getFileWithMetadata(file);
|
||||
const request = {
|
||||
body: data,
|
||||
headers: {} as Record<string, string>,
|
||||
};
|
||||
if (filename) {
|
||||
request.headers["Content-Disposition"] = `attachment; filename="${filename}"`;
|
||||
}
|
||||
if (contentType) {
|
||||
request.headers["Content-Type"] = contentType;
|
||||
}
|
||||
if (contentLength != null) {
|
||||
request.headers["Content-Length"] = contentLength.toString();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
export async function toMultipartDataPart(
|
||||
file: Uploadable,
|
||||
): Promise<{ data: Uploadable.FileLike; filename?: string; contentType?: string }> {
|
||||
const { data, filename, contentType } = await getFileWithMetadata(file, {
|
||||
noSniffFileSize: true,
|
||||
});
|
||||
return {
|
||||
data,
|
||||
filename,
|
||||
contentType,
|
||||
};
|
||||
}
|
||||
|
||||
async function getFileWithMetadata(
|
||||
file: Uploadable,
|
||||
{ noSniffFileSize }: { noSniffFileSize?: boolean } = {},
|
||||
): Promise<Uploadable.WithMetadata> {
|
||||
if (isFileLike(file)) {
|
||||
return getFileWithMetadata(
|
||||
{
|
||||
data: file,
|
||||
},
|
||||
{ noSniffFileSize },
|
||||
);
|
||||
}
|
||||
|
||||
if ("path" in file) {
|
||||
const fs = await import("fs");
|
||||
if (!fs || !fs.createReadStream) {
|
||||
throw new Error("File path uploads are not supported in this environment.");
|
||||
}
|
||||
const data = fs.createReadStream(file.path);
|
||||
const contentLength =
|
||||
file.contentLength ?? (noSniffFileSize === true ? undefined : await tryGetFileSizeFromPath(file.path));
|
||||
const filename = file.filename ?? getNameFromPath(file.path);
|
||||
return {
|
||||
data,
|
||||
filename,
|
||||
contentType: file.contentType,
|
||||
contentLength,
|
||||
};
|
||||
}
|
||||
if ("data" in file) {
|
||||
const data = file.data;
|
||||
const contentLength =
|
||||
file.contentLength ??
|
||||
(await tryGetContentLengthFromFileLike(data, {
|
||||
noSniffFileSize,
|
||||
}));
|
||||
const filename = file.filename ?? tryGetNameFromFileLike(data);
|
||||
return {
|
||||
data,
|
||||
filename,
|
||||
contentType: file.contentType ?? tryGetContentTypeFromFileLike(data),
|
||||
contentLength,
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Invalid FileUpload of type ${typeof file}: ${JSON.stringify(file)}`);
|
||||
}
|
||||
|
||||
function isFileLike(value: unknown): value is Uploadable.FileLike {
|
||||
return (
|
||||
isBuffer(value) ||
|
||||
isArrayBufferView(value) ||
|
||||
isArrayBuffer(value) ||
|
||||
isUint8Array(value) ||
|
||||
isBlob(value) ||
|
||||
isFile(value) ||
|
||||
isStreamLike(value) ||
|
||||
isReadableStream(value)
|
||||
);
|
||||
}
|
||||
|
||||
async function tryGetFileSizeFromPath(path: string): Promise<number | undefined> {
|
||||
try {
|
||||
const fs = await import("fs");
|
||||
if (!fs || !fs.promises || !fs.promises.stat) {
|
||||
return undefined;
|
||||
}
|
||||
const fileStat = await fs.promises.stat(path);
|
||||
return fileStat.size;
|
||||
} catch (_fallbackError) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetNameFromFileLike(data: Uploadable.FileLike): string | undefined {
|
||||
if (isNamedValue(data)) {
|
||||
return data.name;
|
||||
}
|
||||
if (isPathedValue(data)) {
|
||||
return getNameFromPath(data.path.toString());
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function tryGetContentLengthFromFileLike(
|
||||
data: Uploadable.FileLike,
|
||||
{ noSniffFileSize }: { noSniffFileSize?: boolean } = {},
|
||||
): Promise<number | undefined> {
|
||||
if (isBuffer(data)) {
|
||||
return data.length;
|
||||
}
|
||||
if (isArrayBufferView(data)) {
|
||||
return data.byteLength;
|
||||
}
|
||||
if (isArrayBuffer(data)) {
|
||||
return data.byteLength;
|
||||
}
|
||||
if (isBlob(data)) {
|
||||
return data.size;
|
||||
}
|
||||
if (isFile(data)) {
|
||||
return data.size;
|
||||
}
|
||||
if (noSniffFileSize === true) {
|
||||
return undefined;
|
||||
}
|
||||
if (isPathedValue(data)) {
|
||||
return await tryGetFileSizeFromPath(data.path.toString());
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryGetContentTypeFromFileLike(data: Uploadable.FileLike): string | undefined {
|
||||
if (isBlob(data)) {
|
||||
return data.type;
|
||||
}
|
||||
if (isFile(data)) {
|
||||
return data.type;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getNameFromPath(path: string): string | undefined {
|
||||
const lastForwardSlash = path.lastIndexOf("/");
|
||||
const lastBackSlash = path.lastIndexOf("\\");
|
||||
const lastSlashIndex = Math.max(lastForwardSlash, lastBackSlash);
|
||||
return lastSlashIndex >= 0 ? path.substring(lastSlashIndex + 1) : path;
|
||||
}
|
||||
|
||||
type NamedValue = {
|
||||
name: string;
|
||||
} & unknown;
|
||||
|
||||
type PathedValue = {
|
||||
path: string | { toString(): string };
|
||||
} & unknown;
|
||||
|
||||
type StreamLike = {
|
||||
read?: () => unknown;
|
||||
pipe?: (dest: unknown) => unknown;
|
||||
} & unknown;
|
||||
|
||||
function isNamedValue(value: unknown): value is NamedValue {
|
||||
return typeof value === "object" && value != null && "name" in value;
|
||||
}
|
||||
|
||||
function isPathedValue(value: unknown): value is PathedValue {
|
||||
return typeof value === "object" && value != null && "path" in value;
|
||||
}
|
||||
|
||||
function isStreamLike(value: unknown): value is StreamLike {
|
||||
return typeof value === "object" && value != null && ("read" in value || "pipe" in value);
|
||||
}
|
||||
|
||||
function isReadableStream(value: unknown): value is ReadableStream {
|
||||
return typeof value === "object" && value != null && "getReader" in value;
|
||||
}
|
||||
|
||||
function isBuffer(value: unknown): value is Buffer {
|
||||
return typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(value);
|
||||
}
|
||||
|
||||
function isArrayBufferView(value: unknown): value is ArrayBufferView {
|
||||
return typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(value);
|
||||
}
|
||||
|
||||
function isArrayBuffer(value: unknown): value is ArrayBuffer {
|
||||
return typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer;
|
||||
}
|
||||
|
||||
function isUint8Array(value: unknown): value is Uint8Array {
|
||||
return typeof Uint8Array !== "undefined" && value instanceof Uint8Array;
|
||||
}
|
||||
|
||||
function isBlob(value: unknown): value is Blob {
|
||||
return typeof Blob !== "undefined" && value instanceof Blob;
|
||||
}
|
||||
|
||||
function isFile(value: unknown): value is File {
|
||||
return typeof File !== "undefined" && value instanceof File;
|
||||
}
|
||||
2
skyvern-ts/client/src/core/file/index.ts
Normal file
2
skyvern-ts/client/src/core/file/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./file.js";
|
||||
export * from "./types.js";
|
||||
81
skyvern-ts/client/src/core/file/types.ts
Normal file
81
skyvern-ts/client/src/core/file/types.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* A file that can be uploaded. Can be a file-like object (stream, buffer, blob, etc.),
|
||||
* a path to a file, or an object with a file-like object and metadata.
|
||||
*/
|
||||
export type Uploadable = Uploadable.FileLike | Uploadable.FromPath | Uploadable.WithMetadata;
|
||||
|
||||
export namespace Uploadable {
|
||||
/**
|
||||
* Various file-like objects that can be used to upload a file.
|
||||
*/
|
||||
export type FileLike =
|
||||
| ArrayBuffer
|
||||
| ArrayBufferLike
|
||||
| ArrayBufferView
|
||||
| Uint8Array
|
||||
| import("buffer").Buffer
|
||||
| import("buffer").Blob
|
||||
| import("buffer").File
|
||||
| import("stream").Readable
|
||||
| import("stream/web").ReadableStream
|
||||
| globalThis.Blob
|
||||
| globalThis.File
|
||||
| ReadableStream;
|
||||
|
||||
/**
|
||||
* A file path with optional metadata, used for uploading a file from the file system.
|
||||
*/
|
||||
export type FromPath = {
|
||||
/** The path to the file to upload */
|
||||
path: string;
|
||||
/**
|
||||
* Optional override for the file name (defaults to basename of path).
|
||||
* This is used to set the `Content-Disposition` header in upload requests.
|
||||
*/
|
||||
filename?: string;
|
||||
/**
|
||||
* Optional MIME type of the file (e.g., 'image/jpeg', 'text/plain').
|
||||
* This is used to set the `Content-Type` header in upload requests.
|
||||
*/
|
||||
contentType?: string;
|
||||
/**
|
||||
* Optional file size in bytes.
|
||||
* If not provided, the file size will be determined from the file system.
|
||||
* The content length is used to set the `Content-Length` header in upload requests.
|
||||
*/
|
||||
contentLength?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* A file-like object with metadata, used for uploading files.
|
||||
*/
|
||||
export type WithMetadata = {
|
||||
/** The file data */
|
||||
data: FileLike;
|
||||
/**
|
||||
* Optional override for the file name (defaults to basename of path).
|
||||
* This is used to set the `Content-Disposition` header in upload requests.
|
||||
*/
|
||||
filename?: string;
|
||||
/**
|
||||
* Optional MIME type of the file (e.g., 'image/jpeg', 'text/plain').
|
||||
* This is used to set the `Content-Type` header in upload requests.
|
||||
*
|
||||
* If not provided, the content type may be determined from the data itself.
|
||||
* * If the data is a `File`, `Blob`, or similar, the content type will be determined from the file itself, if the type is set.
|
||||
* * Any other data type will not have a content type set, and the upload request will use `Content-Type: application/octet-stream` instead.
|
||||
*/
|
||||
contentType?: string;
|
||||
/**
|
||||
* Optional file size in bytes.
|
||||
* The content length is used to set the `Content-Length` header in upload requests.
|
||||
* If the content length is not provided and cannot be determined, the upload request will not include the `Content-Length` header, but will use `Transfer-Encoding: chunked` instead.
|
||||
*
|
||||
* If not provided, the file size will be determined depending on the data type.
|
||||
* * If the data is of type `fs.ReadStream` (`createReadStream`), the size will be determined from the file system.
|
||||
* * If the data is a `Buffer`, `ArrayBuffer`, `Uint8Array`, `Blob`, `File`, or similar, the size will be determined from the data itself.
|
||||
* * If the data is a `Readable` or `ReadableStream`, the size will not be determined.
|
||||
*/
|
||||
contentLength?: number;
|
||||
};
|
||||
}
|
||||
140
skyvern-ts/client/src/core/form-data-utils/FormDataWrapper.ts
Normal file
140
skyvern-ts/client/src/core/form-data-utils/FormDataWrapper.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { toMultipartDataPart, type Uploadable } from "../../core/file/index.js";
|
||||
import { toJson } from "../../core/json.js";
|
||||
import { RUNTIME } from "../runtime/index.js";
|
||||
|
||||
interface FormDataRequest<Body> {
|
||||
body: Body;
|
||||
headers: Record<string, string>;
|
||||
duplex?: "half";
|
||||
}
|
||||
|
||||
export async function newFormData(): Promise<FormDataWrapper> {
|
||||
return new FormDataWrapper();
|
||||
}
|
||||
|
||||
export class FormDataWrapper {
|
||||
private fd: FormData = new FormData();
|
||||
|
||||
public async setup(): Promise<void> {
|
||||
// noop
|
||||
}
|
||||
|
||||
public append(key: string, value: unknown): void {
|
||||
this.fd.append(key, String(value));
|
||||
}
|
||||
|
||||
public async appendFile(key: string, value: Uploadable): Promise<void> {
|
||||
const { data, filename, contentType } = await toMultipartDataPart(value);
|
||||
const blob = await convertToBlob(data, contentType);
|
||||
if (filename) {
|
||||
this.fd.append(key, blob, filename);
|
||||
} else {
|
||||
this.fd.append(key, blob);
|
||||
}
|
||||
}
|
||||
|
||||
public getRequest(): FormDataRequest<FormData> {
|
||||
return {
|
||||
body: this.fd,
|
||||
headers: {},
|
||||
duplex: "half" as const,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
type StreamLike = {
|
||||
read?: () => unknown;
|
||||
pipe?: (dest: unknown) => unknown;
|
||||
} & unknown;
|
||||
|
||||
function isStreamLike(value: unknown): value is StreamLike {
|
||||
return typeof value === "object" && value != null && ("read" in value || "pipe" in value);
|
||||
}
|
||||
|
||||
function isReadableStream(value: unknown): value is ReadableStream {
|
||||
return typeof value === "object" && value != null && "getReader" in value;
|
||||
}
|
||||
|
||||
function isBuffer(value: unknown): value is Buffer {
|
||||
return typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(value);
|
||||
}
|
||||
|
||||
function isArrayBufferView(value: unknown): value is ArrayBufferView {
|
||||
return ArrayBuffer.isView(value);
|
||||
}
|
||||
|
||||
async function streamToBuffer(stream: unknown): Promise<Buffer> {
|
||||
if (RUNTIME.type === "node") {
|
||||
const { Readable } = await import("stream");
|
||||
|
||||
if (stream instanceof Readable) {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
}
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
}
|
||||
|
||||
if (isReadableStream(stream)) {
|
||||
const reader = stream.getReader();
|
||||
const chunks: Uint8Array[] = [];
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
chunks.push(value);
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
|
||||
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
||||
const result = new Uint8Array(totalLength);
|
||||
let offset = 0;
|
||||
for (const chunk of chunks) {
|
||||
result.set(chunk, offset);
|
||||
offset += chunk.length;
|
||||
}
|
||||
|
||||
return Buffer.from(result);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Unsupported stream type: ${typeof stream}. Expected Node.js Readable stream or Web ReadableStream.`,
|
||||
);
|
||||
}
|
||||
|
||||
async function convertToBlob(value: unknown, contentType?: string): Promise<Blob> {
|
||||
if (isStreamLike(value) || isReadableStream(value)) {
|
||||
const buffer = await streamToBuffer(value);
|
||||
return new Blob([buffer], { type: contentType });
|
||||
}
|
||||
|
||||
if (value instanceof Blob) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (isBuffer(value)) {
|
||||
return new Blob([value], { type: contentType });
|
||||
}
|
||||
|
||||
if (value instanceof ArrayBuffer) {
|
||||
return new Blob([value], { type: contentType });
|
||||
}
|
||||
|
||||
if (isArrayBufferView(value)) {
|
||||
return new Blob([value], { type: contentType });
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
return new Blob([value], { type: contentType });
|
||||
}
|
||||
|
||||
if (typeof value === "object" && value !== null) {
|
||||
return new Blob([toJson(value)], { type: contentType ?? "application/json" });
|
||||
}
|
||||
|
||||
return new Blob([String(value)], { type: contentType });
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { toQueryString } from "../url/qs.js";
|
||||
|
||||
export function encodeAsFormParameter(value: unknown): Record<string, string> {
|
||||
const stringified = toQueryString(value, { encode: false });
|
||||
|
||||
const keyValuePairs = stringified.split("&").map((pair) => {
|
||||
const [key, value] = pair.split("=");
|
||||
return [key, value] as const;
|
||||
});
|
||||
|
||||
return Object.fromEntries(keyValuePairs);
|
||||
}
|
||||
2
skyvern-ts/client/src/core/form-data-utils/index.ts
Normal file
2
skyvern-ts/client/src/core/form-data-utils/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { encodeAsFormParameter } from "./encodeAsFormParameter.js";
|
||||
export * from "./FormDataWrapper.js";
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from "./fetcher/index.js";
|
||||
export * as file from "./file/index.js";
|
||||
export * from "./form-data-utils/index.js";
|
||||
export * from "./runtime/index.js";
|
||||
export * as url from "./url/index.js";
|
||||
|
||||
1
skyvern-ts/client/src/exports.ts
Normal file
1
skyvern-ts/client/src/exports.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./core/exports.js";
|
||||
@@ -3,5 +3,6 @@ export type { BaseClientOptions, BaseRequestOptions } from "./BaseClient.js";
|
||||
export { SkyvernClient } from "./Client.js";
|
||||
export { SkyvernEnvironment } from "./environments.js";
|
||||
export { SkyvernError, SkyvernTimeoutError } from "./errors/index.js";
|
||||
export * from "./exports.js";
|
||||
export { Skyvern, SkyvernBrowser, SkyvernBrowserPageAgent, SkyvernBrowserPageAi } from "./library/index.js";
|
||||
export type { SkyvernOptions, SkyvernBrowserPage } from "./library/index.js";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const SDK_VERSION = "1.0.3";
|
||||
export const SDK_VERSION = "1.0.6";
|
||||
|
||||
Reference in New Issue
Block a user