diff --git a/templates/web/src/client.ts.twig b/templates/web/src/client.ts.twig index f952c31c2..2d82e79fe 100644 --- a/templates/web/src/client.ts.twig +++ b/templates/web/src/client.ts.twig @@ -3,83 +3,275 @@ import { fetch } from 'cross-fetch'; import { Models } from './models'; import { Service } from './service'; +/** + * Payload type representing a key-value pair with string keys and any values. + */ type Payload = { [key: string]: any; } +/** + * Headers type representing a key-value pair with string keys and string values. + */ type Headers = { [key: string]: string; } +/** + * Realtime response structure with different types. + */ type RealtimeResponse = { + /** + * Type of the response: 'error', 'event', 'connected', or 'response'. + */ type: 'error' | 'event' | 'connected' | 'response'; + + /** + * Data associated with the response based on the response type. + */ data: RealtimeResponseAuthenticated | RealtimeResponseConnected | RealtimeResponseError | RealtimeResponseEvent; } +/** + * Realtime request structure for authentication. + */ type RealtimeRequest = { + /** + * Type of the request: 'authentication'. + */ type: 'authentication'; + + /** + * Data required for authentication. + */ data: RealtimeRequestAuthenticate; } +/** + * Realtime event response structure with generic payload type. + */ export type RealtimeResponseEvent = { + /** + * List of event names associated with the response. + */ events: string[]; + + /** + * List of channel names associated with the response. + */ channels: string[]; + + /** + * Timestamp indicating the time of the event. + */ timestamp: number; + + /** + * Payload containing event-specific data. + */ payload: T; } +/** + * Realtime response structure for errors. + */ type RealtimeResponseError = { + /** + * Numeric error code indicating the type of error. + */ code: number; + + /** + * Error message describing the encountered error. + */ message: string; } +/** + * Realtime response structure for a successful connection. + */ type RealtimeResponseConnected = { + /** + * List of channels the user is connected to. + */ channels: string[]; + + /** + * User object representing the connected user (optional). + */ user?: object; } +/** + * Realtime response structure for authenticated connections. + */ type RealtimeResponseAuthenticated = { + /** + * Destination channel for the response. + */ to: string; + + /** + * Boolean indicating the success of the authentication process. + */ success: boolean; + + /** + * User object representing the authenticated user. + */ user: object; } +/** + * Realtime request structure for authentication. + */ type RealtimeRequestAuthenticate = { + /** + * Session identifier for authentication. + */ session: string; } +/** + * Realtime interface representing the structure of a realtime communication object. + */ type Realtime = { + /** + * WebSocket instance for realtime communication. + */ socket?: WebSocket; + + /** + * Timeout duration for communication operations. + */ timeout?: number; + + /** + * URL for establishing the WebSocket connection. + */ url?: string; + + /** + * Last received message from the realtime server. + */ lastMessage?: RealtimeResponse; + + /** + * Set of channel names the client is subscribed to. + */ channels: Set; + + /** + * Map of subscriptions containing channel names and corresponding callback functions. + */ subscriptions: Map) => void }>; + + /** + * Counter for managing subscriptions. + */ subscriptionsCounter: number; + + /** + * Boolean indicating whether automatic reconnection is enabled. + */ reconnect: boolean; + + /** + * Number of reconnection attempts made. + */ reconnectAttempts: number; + + /** + * Function to get the timeout duration for communication operations. + */ getTimeout: () => number; + + /** + * Function to establish a WebSocket connection. + */ connect: () => void; + + /** + * Function to create a new WebSocket instance. + */ createSocket: () => void; + + /** + * Function to clean up resources associated with specified channels. + * + * @param {string[]} channels - List of channel names to clean up. + */ cleanUp: (channels: string[]) => void; + + /** + * Function to handle incoming messages from the WebSocket connection. + * + * @param {MessageEvent} event - Event containing the received message. + */ onMessage: (event: MessageEvent) => void; } +/** + * Type representing upload progress information. + */ export type UploadProgress = { + /** + * Identifier for the upload progress. + */ $id: string; + + /** + * Current progress of the upload (in percentage). + */ progress: number; + + /** + * Total size uploaded (in bytes) during the upload process. + */ sizeUploaded: number; + + /** + * Total number of chunks that need to be uploaded. + */ chunksTotal: number; + + /** + * Number of chunks that have been successfully uploaded. + */ chunksUploaded: number; } +/** + * Exception thrown by the {{language.params.packageName}} package + */ class {{spec.title | caseUcfirst}}Exception extends Error { + /** + * The error code associated with the exception. + */ code: number; + + /** + * The response string associated with the exception. + */ response: string; + + /** + * Error type. + * See [Error Types]({{sdk.url}}/docs/response-codes#errorTypes) for more information. + */ type: string; + + /** + * Initializes a {{spec.title | caseUcfirst}} Exception. + * + * @param {string} message - The error message. + * @param {number} code - The error code. Default is 0. + * @param {string} type - The error type. Default is an empty string. + * @param {string} response - The response string. Default is an empty string. + */ constructor(message: string, code: number = 0, type: string = '', response: string = '') { super(message); this.name = '{{spec.title | caseUcfirst}}Exception'; @@ -90,7 +282,13 @@ class {{spec.title | caseUcfirst}}Exception extends Error { } } +/** + * Client that handles requests to {{spec.title | caseUcfirst}} + */ class Client { + /** + * Holds configuration such as project. + */ config = { endpoint: '{{ spec.endpoint }}', endpointRealtime: '', @@ -98,6 +296,10 @@ class Client { {{ header.key | caseLower }}: '', {% endfor %} }; + + /** + * Custom headers for API requests. + */ headers: Headers = { 'x-sdk-name': '{{ sdk.name }}', 'x-sdk-platform': '{{ sdk.platform }}', @@ -336,6 +538,19 @@ class Client { } } + /** + * Call API endpoint with the specified method, URL, headers, and parameters. + * + * @param {string} method - HTTP method (e.g., 'GET', 'POST', 'PUT', 'DELETE'). + * @param {URL} url - The URL of the API endpoint. + * @param {Headers} headers - Custom headers for the API request. + * @param {Payload} params - Request parameters. + * @returns {Promise} - A promise that resolves with the response data. + * + * @typedef {Object} Payload - Request payload data. + * @property {string} key - The key. + * @property {string} value - The value. + */ async call(method: string, url: URL, headers: Headers = {}, params: Payload = {}): Promise { method = method.toUpperCase(); diff --git a/templates/web/src/id.ts.twig b/templates/web/src/id.ts.twig index 199f00a4f..33495cc8e 100644 --- a/templates/web/src/id.ts.twig +++ b/templates/web/src/id.ts.twig @@ -1,6 +1,13 @@ +/** + * Helper class to generate ID strings for resources. + */ export class ID { - // Generate an hex ID based on timestamp - // Recreated from https://www.php.net/manual/en/function.uniqid.php + /** + * Generate an hex ID based on timestamp. + * Recreated from https://www.php.net/manual/en/function.uniqid.php + * + * @returns {string} + */ static #hexTimestamp(): string { const now = new Date(); const sec = Math.floor(now.getTime() / 1000); @@ -11,10 +18,22 @@ export class ID { return hexTimestamp; } + /** + * Uses the provided ID as the ID for the resource. + * + * @param {string} id + * @returns {string} + */ public static custom(id: string): string { return id } + /** + * Have Appwrite generate a unique ID for you. + * + * @param {number} padding. Default is 7. + * @returns {string} + */ public static unique(padding: number = 7): string { // Generate a unique ID with padding to have a longer ID const baseId = ID.#hexTimestamp(); diff --git a/templates/web/src/index.ts.twig b/templates/web/src/index.ts.twig index 27cb52883..79b35c1ee 100644 --- a/templates/web/src/index.ts.twig +++ b/templates/web/src/index.ts.twig @@ -1,3 +1,10 @@ +/** + * {{spec.title | caseUcfirst}} {{sdk.name}} SDK + * + * This SDK is compatible with Appwrite server version {{spec.version | split('.') | slice(0,2) | join('.') ~ '.x' }}. + * For older versions, please check + * [previous releases](https://github.com/{{sdk.gitUserName}}/{{sdk.gitRepoName}}/releases). + */ export { Client, Query, {{spec.title | caseUcfirst}}Exception } from './client'; {% for service in spec.services %} export { {{service.name | caseUcfirst}} } from './services/{{service.name | caseDash}}'; diff --git a/templates/web/src/models.ts.twig b/templates/web/src/models.ts.twig index 4b0f63f8b..9ce8b0c59 100644 --- a/templates/web/src/models.ts.twig +++ b/templates/web/src/models.ts.twig @@ -1,3 +1,6 @@ +/** + * {{spec.title | caseUcfirst}} Models + */ export namespace Models { {% for definition in spec.definitions %} /** diff --git a/templates/web/src/permission.ts.twig b/templates/web/src/permission.ts.twig index bfc330a16..94d9ceddd 100644 --- a/templates/web/src/permission.ts.twig +++ b/templates/web/src/permission.ts.twig @@ -1,22 +1,57 @@ +/** + * Helper class to generate permission strings for resources. + */ export class Permission { - + /** + * Generate read permission string for the provided role. + * + * @param {string} role + * @returns {string} + */ static read = (role: string): string => { - return `read("${role}")` + return `read("${role}")`; } + /** + * Generate write permission string for the provided role. + * + * This is an alias of update, delete, and possibly create. + * Don't use write in combination with update, delete, or create. + * + * @param {string} role + * @returns {string} + */ static write = (role: string): string => { - return `write("${role}")` + return `write("${role}")`; } + /** + * Generate create permission string for the provided role. + * + * @param {string} role + * @returns {string} + */ static create = (role: string): string => { - return `create("${role}")` + return `create("${role}")`; } + /** + * Generate update permission string for the provided role. + * + * @param {string} role + * @returns {string} + */ static update = (role: string): string => { - return `update("${role}")` + return `update("${role}")`; } + /** + * Generate delete permission string for the provided role. + * + * @param {string} role + * @returns {string} + */ static delete = (role: string): string => { - return `delete("${role}")` + return `delete("${role}")`; } } diff --git a/templates/web/src/query.ts.twig b/templates/web/src/query.ts.twig index 229d6c858..acad03823 100644 --- a/templates/web/src/query.ts.twig +++ b/templates/web/src/query.ts.twig @@ -3,11 +3,21 @@ export type QueryTypesList = string[] | number[] | boolean[] | Query[]; export type QueryTypes = QueryTypesSingle | QueryTypesList; type AttributesTypes = string | string[]; +/** + * Helper class to generate query strings. + */ export class Query { method: string; attribute: AttributesTypes | undefined; values: QueryTypesList | undefined; + /** + * Constructor for Query class. + * + * @param {string} method + * @param {AttributesTypes} attribute + * @param {QueryTypes} values + */ constructor( method: string, attribute?: AttributesTypes, @@ -25,6 +35,11 @@ export class Query { } } + /** + * Convert the query object to a JSON string. + * + * @returns {string} + */ toString(): string { return JSON.stringify({ method: this.method, @@ -33,69 +48,214 @@ export class Query { }); } + /** + * Filter resources where attribute is equal to value. + * + * @param {string} attribute + * @param {QueryTypes} value + * @returns {string} + */ static equal = (attribute: string, value: QueryTypes): string => new Query("equal", attribute, value).toString(); + /** + * Filter resources where attribute is not equal to value. + * + * @param {string} attribute + * @param {QueryTypes} value + * @returns {string} + */ static notEqual = (attribute: string, value: QueryTypes): string => new Query("notEqual", attribute, value).toString(); + /** + * Filter resources where attribute is less than value. + * + * @param {string} attribute + * @param {QueryTypes} value + * @returns {string} + */ static lessThan = (attribute: string, value: QueryTypes): string => new Query("lessThan", attribute, value).toString(); + /** + * Filter resources where attribute is less than or equal to value. + * + * @param {string} attribute + * @param {QueryTypes} value + * @returns {string} + */ static lessThanEqual = (attribute: string, value: QueryTypes): string => new Query("lessThanEqual", attribute, value).toString(); + /** + * Filter resources where attribute is greater than value. + * + * @param {string} attribute + * @param {QueryTypes} value + * @returns {string} + */ static greaterThan = (attribute: string, value: QueryTypes): string => new Query("greaterThan", attribute, value).toString(); + /** + * Filter resources where attribute is greater than or equal to value. + * + * @param {string} attribute + * @param {QueryTypes} value + * @returns {string} + */ static greaterThanEqual = (attribute: string, value: QueryTypes): string => new Query("greaterThanEqual", attribute, value).toString(); + /** + * Filter resources where attribute is null. + * + * @param {string} attribute + * @returns {string} + */ static isNull = (attribute: string): string => new Query("isNull", attribute).toString(); + /** + * Filter resources where attribute is not null. + * + * @param {string} attribute + * @returns {string} + */ static isNotNull = (attribute: string): string => new Query("isNotNull", attribute).toString(); - static between = (attribute: string, start: string | number, end: string | number) => + /** + * Filter resources where attribute is between start and end (inclusive). + * + * @param {string} attribute + * @param {string | number} start + * @param {string | number} end + * @returns {string} + */ + static between = (attribute: string, start: string | number, end: string | number): string => new Query("between", attribute, [start, end] as QueryTypesList).toString(); + /** + * Filter resources where attribute starts with value. + * + * @param {string} attribute + * @param {string} value + * @returns {string} + */ static startsWith = (attribute: string, value: string): string => new Query("startsWith", attribute, value).toString(); + /** + * Filter resources where attribute ends with value. + * + * @param {string} attribute + * @param {string} value + * @returns {string} + */ static endsWith = (attribute: string, value: string): string => new Query("endsWith", attribute, value).toString(); + /** + * Specify which attributes should be returned by the API call. + * + * @param {string[]} attributes + * @returns {string} + */ static select = (attributes: string[]): string => new Query("select", undefined, attributes).toString(); + /** + * Filter resources by searching attribute for value. + * A fulltext index on attribute is required for this query to work. + * + * @param {string} attribute + * @param {string} value + * @returns {string} + */ static search = (attribute: string, value: string): string => new Query("search", attribute, value).toString(); + /** + * Sort results by attribute descending. + * + * @param {string} attribute + * @returns {string} + */ static orderDesc = (attribute: string): string => new Query("orderDesc", attribute).toString(); + /** + * Sort results by attribute ascending. + * + * @param {string} attribute + * @returns {string} + */ static orderAsc = (attribute: string): string => new Query("orderAsc", attribute).toString(); + /** + * Return results after documentId. + * + * @param {string} documentId + * @returns {string} + */ static cursorAfter = (documentId: string): string => new Query("cursorAfter", undefined, documentId).toString(); + /** + * Return results before documentId. + * + * @param {string} documentId + * @returns {string} + */ static cursorBefore = (documentId: string): string => new Query("cursorBefore", undefined, documentId).toString(); + /** + * Return only limit results. + * + * @param {number} limit + * @returns {string} + */ static limit = (limit: number): string => new Query("limit", undefined, limit).toString(); + /** + * Filter resources by skipping the first offset results. + * + * @param {number} offset + * @returns {string} + */ static offset = (offset: number): string => new Query("offset", undefined, offset).toString(); + /** + * Filter resources where attribute contains the specified value. + * + * @param {string} attribute + * @param {string | string[]} value + * @returns {string} + */ static contains = (attribute: string, value: string | string[]): string => new Query("contains", attribute, value).toString(); + /** + * Combine multiple queries using logical OR operator. + * + * @param {string[]} queries + * @returns {string} + */ static or = (queries: string[]) => new Query("or", undefined, queries.map((query) => JSON.parse(query))).toString(); + /** + * Combine multiple queries using logical AND operator. + * + * @param {string[]} queries + * @returns {string} + */ static and = (queries: string[]) => new Query("and", undefined, queries.map((query) => JSON.parse(query))).toString(); } diff --git a/templates/web/src/service.ts.twig b/templates/web/src/service.ts.twig index fe1769929..8b360685e 100644 --- a/templates/web/src/service.ts.twig +++ b/templates/web/src/service.ts.twig @@ -2,6 +2,9 @@ import { Client } from './client'; import type { Payload } from './client'; export class Service { + /** + * The size for chunked uploads in bytes. + */ static CHUNK_SIZE = 5*1024*1024; // 5MB client: Client;