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

fix: multipart testing #24

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/examples/functions/create-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const functions = new Functions(client);

const response = await functions.createDeployment(
'<FUNCTION_ID>', // functionId
InputFile.fromPath('/path/to/file.png', 'file.png'), // code
Payload.fromFile('/path/to/file.png'), // code
false, // activate
'<ENTRYPOINT>', // entrypoint (optional)
'<COMMANDS>' // commands (optional)
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/functions/create-execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const functions = new Functions(client);

const response = await functions.createExecution(
'<FUNCTION_ID>', // functionId
'<BODY>', // body (optional)
Payload.fromJson({ x: "y" }), // body (optional)
false, // async (optional)
'<PATH>', // path (optional)
ExecutionMethod.GET, // method (optional)
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/storage/create-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ const storage = new Storage(client);
const response = await storage.createFile(
'<BUCKET_ID>', // bucketId
'<FILE_ID>', // fileId
InputFile.fromPath('/path/to/file.png', 'file.png'), // file
Payload.fromFile('/path/to/file.png'), // file
["read("any")"] // permissions (optional)
);
4 changes: 2 additions & 2 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Query } from "./src/query.ts";
import { Permission } from "./src/permission.ts";
import { Role } from "./src/role.ts";
import { ID } from "./src/id.ts";
import { InputFile } from "./src/inputFile.ts";
import { Payload } from "./src/payload.ts";
import { AppwriteException } from "./src/exception.ts";
import { Account } from "./src/services/account.ts";
import { Avatars } from "./src/services/avatars.ts";
Expand Down Expand Up @@ -41,7 +41,7 @@ export {
Permission,
Role,
ID,
InputFile,
Payload,
AppwriteException,
Account,
Avatars,
Expand Down
50 changes: 43 additions & 7 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AppwriteException } from './exception.ts';
import { Payload } from './payload.ts';
import { getBoundary, parse as parseMultipart } from './multipart.ts';

export interface Payload {
export interface Params {
[key: string]: any;
}

Expand All @@ -9,13 +11,13 @@ export class Client {
static DENO_READ_CHUNK_SIZE = 16384; // 16kb; refference: https://github.com/denoland/deno/discussions/9906

endpoint: string = 'https://cloud.appwrite.io/v1';
headers: Payload = {
headers: Params = {
'content-type': '',
'user-agent' : `AppwriteDenoSDK/12.1.0 (${Deno.build.os}; ${Deno.build.arch})`,
'user-agent' : `AppwriteDenoSDK/13.0.0 (${Deno.build.os}; ${Deno.build.arch})`,
'x-sdk-name': 'Deno',
'x-sdk-platform': 'server',
'x-sdk-language': 'deno',
'x-sdk-version': '12.1.0',
'x-sdk-version': '13.0.0',
'X-Appwrite-Response-Format':'1.6.0',
};

Expand Down Expand Up @@ -128,7 +130,7 @@ export class Client {
return this;
}

async call(method: string, path: string = "", headers: Payload = {}, params: Payload = {}, responseType: string = "json") {
async call(method: string, path: string = "", headers: Params = {}, params: Params = {}, responseType: string = "json") {
headers = {...this.headers, ...headers};
const url = new URL(this.endpoint + path);

Expand Down Expand Up @@ -192,6 +194,40 @@ export class Client {
return response.headers.get("location");
}

if (response.headers.get('content-type')?.includes('multipart/form-data')) {
const boundary = getBoundary(
response.headers.get("content-type") || ""
);

const body = new Uint8Array(await response.arrayBuffer());
const parts = parseMultipart(body, boundary);
const partsObject: { [key: string]: any } = {};

for (const part of parts) {
if (!part.name) {
continue;
}
if (part.name === "responseBody") {
partsObject[part.name] = Payload.fromBinary(part.data, part.filename);
} else if (part.name === "responseStatusCode") {
partsObject[part.name] = parseInt(part.data.toString());
} else if (part.name === "duration") {
partsObject[part.name] = parseFloat(part.data.toString());
} else if (part.type === 'application/json') {
try {
partsObject[part.name] = JSON.parse(part.data.toString());
} catch (e) {
throw new Error(`Error parsing JSON for part ${part.name}: ${e instanceof Error ? e.message : 'Unknown error'}`);
}
} else {
partsObject[part.name] = new TextDecoder().decode(part.data);
}
}

const data = partsObject;
return data;
}

const text = await response.text();
let json = undefined;
try {
Expand All @@ -202,8 +238,8 @@ export class Client {
return json;
}

static flatten(data: Payload, prefix = ''): Payload {
let output: Payload = {};
static flatten(data: Params, prefix = ''): Params {
let output: Params = {};

for (const [key, value] of Object.entries(data)) {
let finalKey = prefix ? prefix + '[' + key +']' : key;
Expand Down
1 change: 1 addition & 0 deletions src/enums/image-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export enum ImageFormat {
Gif = 'gif',
Png = 'png',
Webp = 'webp',
Avif = 'avif',
}
3 changes: 3 additions & 0 deletions src/enums/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export enum Runtime {
Python311 = 'python-3.11',
Python312 = 'python-3.12',
PythonMl311 = 'python-ml-3.11',
Deno121 = 'deno-1.21',
Deno124 = 'deno-1.24',
Deno135 = 'deno-1.35',
Deno140 = 'deno-1.40',
Dart215 = 'dart-2.15',
Dart216 = 'dart-2.16',
Expand Down
46 changes: 0 additions & 46 deletions src/inputFile.ts

This file was deleted.

92 changes: 91 additions & 1 deletion src/models.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Payload } from './payload.ts';

export namespace Models {
/**
* Documents List
Expand Down Expand Up @@ -487,6 +489,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* Attribute size.
*/
Expand Down Expand Up @@ -524,6 +534,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* Minimum value to enforce for new documents.
*/
Expand Down Expand Up @@ -565,6 +583,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* Minimum value to enforce for new documents.
*/
Expand Down Expand Up @@ -606,6 +632,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* Default value for attribute when not provided. Cannot be set when attribute is required.
*/
Expand Down Expand Up @@ -639,6 +673,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* String format.
*/
Expand Down Expand Up @@ -676,6 +718,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* Array of elements in enumerated type.
*/
Expand Down Expand Up @@ -717,6 +767,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* String format.
*/
Expand Down Expand Up @@ -754,6 +812,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* String format.
*/
Expand Down Expand Up @@ -791,6 +857,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* ISO 8601 format.
*/
Expand Down Expand Up @@ -828,6 +902,14 @@ export namespace Models {
* Is attribute an array?
*/
array?: boolean;
/**
* Attribute creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Attribute update date in ISO 8601 format.
*/
$updatedAt: string;
/**
* The ID of the related collection.
*/
Expand Down Expand Up @@ -881,6 +963,14 @@ export namespace Models {
* Index orders.
*/
orders?: string[];
/**
* Index creation date in ISO 8601 format.
*/
$createdAt: string;
/**
* Index update date in ISO 8601 format.
*/
$updatedAt: string;
}
/**
* Document
Expand Down Expand Up @@ -1917,7 +2007,7 @@ export namespace Models {
/**
* HTTP response body. This will return empty unless execution is created as synchronous.
*/
responseBody: string;
responseBody: Payload;
/**
* HTTP response headers as a key-value object. This will return only whitelisted headers. All headers are returned if execution is created as synchronous.
*/
Expand Down
Loading